主页 > 开源代码  > 

多进程服务器和多线程服务器


多进程服务器 #include<myhead.h> #define PORT 9999 //端口号 #define IP "192.168.10.116" //IP地址 //定义信号处理函数,用于回收僵尸进程 void handler(int signo) { if(signo == SIGCHLD) { while(waitpid(-1, NULL, WNOHANG) > 0 ); } } //定义处理客户端操作的函数 int deal_cli_msg(int newfd, struct sockaddr_in cin) { //5、收发数据 char rbuf[128] = ""; //读取消息的容器 while(1) { //清空内容 bzero(rbuf, sizeof(rbuf)); int res = recv(newfd, rbuf, sizeof(rbuf), 0); if(res == 0) { printf("客户端下线\n"); break; } printf("[%s:%d] : %s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), rbuf); //链接一个字符串后发回去 strcat(rbuf, "*_*"); send(newfd, rbuf, sizeof(rbuf), 0); //功能:向newfd文件描述符中以阻塞形式写入数据 } close(newfd); return 0; } /**********************************主程序***************************************/ int main(int argc, const char *argv[]) { //将SIGCHLD信号与信号处理函数进行绑定 if(signal(SIGCHLD, handler) == SIG_ERR) { perror("signal error"); return -1; } //1、创建套接字 int sfd = -1; //功能创建一个支持TCP通信的套接字 //AF_INET:表示跨主机的IPv4的通信 //SOCK_STREAM:表示支持TCP通信 if((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket error"); return -1; } printf("sfd = %d\n", sfd); //? //设置端口号快速重用 int reuse = 1; if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1) { perror("setsockopt error"); return -1; } //2、绑定地址信息结构体(必须) //2.1 填充地址信息结构体 struct sockaddr_in sin; sin.sin_family = AF_INET; //地址族为IPv4 sin.sin_port = htons(PORT); //端口号,需要转换网络字节序 sin.sin_addr.s_addr = inet_addr(IP); //IP地址 //2.2绑定工作 if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1) { perror("bind error"); return -1; } printf("bind success _%d_%s_%s\n", __LINE__, __FILE__, __func__); //3、将套接字设置成被动监听状态 if(listen(sfd, 128) == -1) { perror("listen error"); return -1; } printf("listen success _%d_%s_%s\n", __LINE__, __FILE__, __func__); //4、接收链接请求 //4.1 定义用于接收客户端地址信息的结构体变量 struct sockaddr_in cin; socklen_t socklen = sizeof(cin); //接收长度 //4.2 接收客户端链接请求 int newfd = -1; //用于跟客户端通信的套接字文件描述符 pid_t pid = -1; //接收子进程pid号 while(1) { //fork() 接收客户端链接请求 //当执行到accept时,系统会给该函数预分配一个文件描述符(按最小未使用原则) //所以,在该函数阻塞时,即使有旧的客户端退,释放了文件描述符,也不会再使用新释放的文件描述符 //下一次阻塞时,会预选上一次释放的文件描述符 if( (newfd=accept(sfd, (struct sockaddr*)&cin, &socklen)) == -1) { perror("accept error"); return -1; } printf("[%s:%d] 连接成功, newfd = %d\n", inet_ntoa(cin.sin_addr),\ ntohs(cin.sin_port), newfd); //? //创建子进程用于跟新的客户端进行通信工作 pid = fork(); if(pid > 0) { //父进程用于接收客户端连接请求 //父进程中关闭newfd close(newfd); }else if(pid == 0) { //关闭sfd close(sfd); //调用处理客户端信息的函数 deal_cli_msg(newfd, cin); //退出子进程 exit(EXIT_SUCCESS); }else { perror("fork error"); return -1; } //wait(NULL); //不能使用阻塞方式回收 } //关闭套接字 close(sfd); return 0; } 多线程服务器 #include<myhead.h> #define PORT 9999 //端口号 #define IP "192.168.10.116" //IP地址 //定义向线程体中传递参数的结构体类型 struct pthread_ds { int newfd; //处理客户端的套接字文件描述符 struct sockaddr_in cin; //客户端套接字地址信息结构体变量 }; //定义线程处理函数 void *deal_cli_msg(void *arg) { //分解传过来的参数 int newfd = ((struct pthread_ds*)arg)->newfd; struct sockaddr_in cin = ((struct pthread_ds*)arg)->cin; //5、收发数据 char rbuf[128] = ""; //读取消息的容器 while(1) { //清空内容 bzero(rbuf, sizeof(rbuf)); int res = recv(newfd, rbuf, sizeof(rbuf), 0); if(res == 0) { printf("客户端下线\n"); break; } printf("[%s:%d] : %s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), rbuf); //链接一个字符串后发回去 strcat(rbuf, "*_*"); send(newfd, rbuf, sizeof(rbuf), 0); //功能:向newfd文件描述符中以阻塞形式写入数据 } close(newfd); //退出线程 pthread_exit(NULL); } /****************************主程序***********************/ int main(int argc, const char *argv[]) { //1、创建套接字 int sfd = -1; //功能创建一个支持TCP通信的套接字 //AF_INET:表示跨主机的IPv4的通信 //SOCK_STREAM:表示支持TCP通信 if((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket error"); return -1; } printf("sfd = %d\n", sfd); //? //设置端口号快速重用 int reuse = 1; if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1) { perror("setsockopt error"); return -1; } //2、绑定地址信息结构体(必须) //2.1 填充地址信息结构体 struct sockaddr_in sin; sin.sin_family = AF_INET; //地址族为IPv4 sin.sin_port = htons(PORT); //端口号,需要转换网络字节序 sin.sin_addr.s_addr = inet_addr(IP); //IP地址 //2.2绑定工作 if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1) { perror("bind error"); return -1; } printf("bind success _%d_%s_%s\n", __LINE__, __FILE__, __func__); //3、将套接字设置成被动监听状态 if(listen(sfd, 128) == -1) { perror("listen error"); return -1; } printf("listen success _%d_%s_%s\n", __LINE__, __FILE__, __func__); //4、接收链接请求 //4.1 定义用于接收客户端地址信息的结构体变量 struct sockaddr_in cin; socklen_t socklen = sizeof(cin); //接收长度 //4.2 接收客户端链接请求 int newfd = -1; //用于跟客户端通信的套接字文件描述符 pthread_t tid = -1; //接收线程号 while(1) { //接收客户端链接请求 if( (newfd=accept(sfd, (struct sockaddr*)&cin, &socklen)) == -1) { perror("accept error"); return -1; } printf("[%s:%d] 连接成功, newfd = %d\n", inet_ntoa(cin.sin_addr),\ ntohs(cin.sin_port), newfd); //? //定义一个向线程体传递的结构体变量 struct pthread_ds info = {newfd, cin}; //创建一个分支线程,用于跟客户端进行通信 if(pthread_create(&tid, NULL, deal_cli_msg, &info) != 0) { printf("tid create error\n"); return -1; } //回收线程资源 //pthread_join(tid); //不能使用阻塞形式回收线程资源 pthread_detach(tid); //将线程设置成分离态 } //关闭套接字 close(sfd); return 0; }

标签:

多进程服务器和多线程服务器由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“多进程服务器和多线程服务器