一、问题引入
Linux网络编程:socket & fork()多进程 实现clients/server通信 随笔介绍了通过fork()多进程实现了服务器与多客户端通信。但除了多进程能实现之外,多线程也是一种实现方式。
重要的是,多进程和多线程是涉及操作系统层次。随笔不仅要利用pthread_create()实现多线程编程,也要理解线程和进程的区别。
二、解决过程
client 代码无需修改,请参考 Linux网络编程:socket & fork()多进程 实现clients/server通信
2-1 server 代码
- #include <stdlib.h>
- #include <pthread.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <errno.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <sys/syscall.h>
- #define IP "10.8.198.227"
- #define PORT 8887
- #define gettid() syscall(__NR_gettid)
- #define PTHREAD_MAX_SIZE 3 // 允许最大客户端连接数
- typedef struct PTHREAD_DATA_ST
- {
- pthread_t pthread_id;
- int connfd;
- char socket[128];
- struct sockaddr_in cliaddr;
- }PTHREAD_DATA_ST;
- //static int g_pthread_num = 3; // 允许最大客户端连接数
- static struct PTHREAD_DATA_ST g_pthread_data[PTHREAD_MAX_SIZE];
- static void pthread_data_index_init(void)
- {
- for (int i = 0; i < PTHREAD_MAX_SIZE; i++)
- {
- memset(&g_pthread_data[i], 0 , sizeof(struct PTHREAD_DATA_ST));
- g_pthread_data[i].connfd = -1;
- }
- }
- static int pthread_data_index_find(void)
- {
- int i;
- for (i = 0; i < PTHREAD_MAX_SIZE; i++)
- {
- if (g_pthread_data[i].connfd == -1)
- break;
- }
- return i;
- }
- static int string_toupper(const char *src, int str_len, char *dst)
- {
- int count = 0;
- for (int i = 0; i < str_len; i++)
- {
- dst[i] = toupper(src[i]);
- count++;
- }
- return count;
- }
- void *pthread_handle(void *arg)
- {
- struct PTHREAD_DATA_ST *pthread = (struct PTHREAD_DATA_ST *)arg;
- int connfd = pthread->connfd;
- int recv_len, send_len;
- pid_t tid = gettid();
- char read_buf[1024], write_buf[1024];
- while (1)
- {
- memset(read_buf, 0, sizeof(read_buf));
- memset(write_buf, 0, sizeof(write_buf));
- recv_len = read(connfd, read_buf, sizeof(read_buf));
- if (recv_len <= 0)
- {
- printf("%s close, child %d terminated\n", pthread->socket, tid);
- close(connfd);
- pthread->connfd = -1;
- pthread_exit(NULL);
- }
- printf("%s:%s(%d Byte)\n", pthread->socket, read_buf, recv_len);
- send_len = string_toupper(read_buf, strlen(read_buf), write_buf);
- write(connfd, write_buf, send_len);
- if (strcmp("exit", read_buf) == 0)
- {
- printf("%s exit, child %d terminated\n", pthread->socket, tid);
- close(connfd);
- pthread->connfd = -1;
- pthread_exit(NULL);
- }
- }
- }
- int main(void)
- {
- int listenfd, connfd;
- struct sockaddr_in server_sockaddr;
- struct sockaddr_in client_addr;
- char buf[1024];
- char client_socket[128];
- socklen_t length;
- int idx;
- int opt = 1;
- server_sockaddr.sin_family = AF_INET;
- server_sockaddr.sin_port = htons(PORT);
- server_sockaddr.sin_addr.s_addr = inet_addr(IP);
- listenfd = socket(AF_INET, SOCK_STREAM, 0);
- if (listenfd < 0)
- {
- perror("socket error");
- exit(1);
- }
- // 设置端口复用
- setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
- if (bind(listenfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) < 0)
- {
- perror("bind error");
- exit(1);
- }
- if (listen(listenfd, 5) < 0)
- {
- perror("listen error");
- exit(1);
- }
- pthread_data_index_init();
- while (1)
- {
- // 接受来自客户端的信息
- printf("accept start \n");
- memset(&client_addr, 0, sizeof(client_addr));
- length = sizeof(client_addr);
- if ((connfd = accept(listenfd, (struct sockaddr *)&client_addr, &length)) < 0)
- {
- if (errno == EINTR)
- continue;
- else
- {
- perror("accept error");
- exit(1);
- }
- }
- idx = pthread_data_index_find();
- if (idx == PTHREAD_MAX_SIZE)
- {
- printf("client connected upper limit, refused connect\n");
- close(connfd);
- continue;
- }
- memset(&client_socket, 0, sizeof(client_socket));
- printf("client addr:%s por:%d\n",
- inet_ntop(AF_INET, &client_addr.sin_addr, buf, sizeof(buf)),
- ntohs(client_addr.sin_port));
- snprintf(client_socket, sizeof(client_socket), "client socket (%s:%d)",
- inet_ntop(AF_INET, &client_addr.sin_addr, buf, sizeof(buf)),
- ntohs(client_addr.sin_port));
- g_pthread_data[idx].connfd = connfd;
- g_pthread_data[idx].cliaddr = client_addr;
- strcpy(g_pthread_data[idx].socket, client_socket);
- pthread_create(&(g_pthread_data[idx].pthread_id), NULL, pthread_handle, &(g_pthread_data[idx]));
- pthread_detach(g_pthread_data[idx].pthread_id);
- }
- close(listenfd);
- return EXIT_SUCCESS;
- }
复制代码 2-2 编译运行
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |