目录
一,往期文章
二,代码实现
一,往期文章
【高并发网络通信架构】1.Linux下实现单客户连接的tcp服务端
二,代码实现
关键代码
- 因为accept是阻塞等待客户端连接,当客户端连接成功后才会执行accept后面的代码,所以为实现多个客户端连接,第一步是将accept放在master循环里。
- recv是阻塞型函数,如果不将recv的相关代码放到线程里去,会导致客户端无法与服务端通信。
完整代码
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #define BUFFER_LENGTH 1024 void* threadCommunication(void *arg) { int cfd = *(int*)arg; //客户端文件描述符 while(1) //一直循环是确保一直和服务端通信,并且recv是阻塞函数 { char data[BUFFER_LENGTH] = {0}; int recLen = recv(cfd,data,BUFFER_LENGTH,0); if(recLen < 0){ printf("recv error code: %d codeInfo: %s\n",errno,strerror(errno)); return NULL; }else if(recLen == 0){ //客户端断开连接 printf("client fd %d disconnect\n",cfd); close(cfd); pthread_exit(NULL); break; }else{ printf("recv fd %d data: %s\n",cfd,data); send(cfd,data,recLen,0); //将接收到的数据重新发给客户端 } } return NULL; } int init_server(int port){ //获取服务端fd,通常为3,前面0,1,2用于指定输入,输出,错误值 int sfd = socket(AF_INET,SOCK_STREAM,0); if(-1 == sfd){ printf("socket error code: %d codeInfo: %s\n",errno,strerror(errno)); return -1; } struct sockaddr_in servAddr; memset(&servAddr,0,sizeof(struct sockaddr_in)); servAddr.sin_family = AF_INET; //ipv4 servAddr.sin_addr.s_addr = htonl(INADDR_ANY); //0.0.0.0 servAddr.sin_port = htons(port); //绑定IP和端口号 if(-1 == bind(sfd,(struct sockaddr*)&servAddr,sizeof(struct sockaddr_in))) { printf("bind error code: %d codeInfo: %s\n",errno,strerror(errno)); return -1; } //监听该套接字上的连接 if(-1 == listen(sfd,10)) { printf("listen error code: %d codeInfo: %s\n",errno,strerror(errno)); return -1; } return sfd; } int main(int argc,char *argv[]){ if(argc < 2)return -1; int port = atoi(argv[1]); int sfd = init_server(port); printf("server fd: %d\n",sfd); struct sockaddr_in servAddr; socklen_t len = sizeof(struct sockaddr_in); while (1)//每个服务器至少都有一个主循环 { int cfd = accept(sfd,(struct sockaddr*)&servAddr,&len); pthread_t tid; int flag = pthread_create(&tid,NULL,threadCommunication,(void*)&cfd); if(0 == flag) { printf("client fd: %d ,thread ID: %ld start\n",cfd,tid); } } return 0; }
运行效果
问题思考
- 这种实现方式对于几十几百个客户端并发连接可能没问题,但对于成千上万的客户端进行高并发连接,仍采用这种方式来处理显然是不现实的?下一章介绍。。。