博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
socket通信,server与多客户端通信
阅读量:5930 次
发布时间:2019-06-19

本文共 5570 字,大约阅读时间需要 18 分钟。

近日研究socket 通信,学习了如下的一篇文章:

(向作者致敬)

感觉很好,但还有一点不过瘾,就想着能否加点料:增加多个客户端,让他们一起和服务器端通信。

为了区别各个客户端,把客户端里加入了识别自身hostname的一段。

修改后的代码如下:

server :

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define HELLO_WORLD_SERVER_PORT 6666#define LENGTH_OF_LISTEN_QUEUE 20#define BUFFER_SIZE 1024void reaper(int sig){int status;while( wait3(&status,WNOHANG,(struct rusage*)0) >=0 ) ;}int main(int argc, char **argv){ struct sockaddr_in server_addr; bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htons(INADDR_ANY); server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT); int server_socket = socket(AF_INET,SOCK_STREAM,0); if( server_socket < 0){ printf("Create Socket Failed!"); exit(1); } if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))){ printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT); exit(1); } fprintf(stderr,"Before Main Process listen.\n"); if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) ){ printf("Server Listen Failed!"); exit(1); } fprintf(stderr, "After Main Process listen.\n"); (void)signal(SIGCHLD,reaper); while (1){ struct sockaddr_in client_addr; socklen_t length = sizeof(client_addr); fprintf(stderr,"Before accept. In %d.\n",getpid()); int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length); if ( new_server_socket < 0){ printf("Server Accept Failed!\n"); break; } fprintf(stderr,"After accept. In %d.\n",getpid()); int child_process_pid = fork(); if(child_process_pid == 0 ){ fprintf(stderr,"Child. %d born.\n",getpid()); close(server_socket); char buffer[BUFFER_SIZE]; bzero(buffer, BUFFER_SIZE); strcpy(buffer,"Hello,World! FromServer! "); int pd; pd=getpid(); char cpd[10]; sprintf(cpd,"%d",pd); strcat(buffer,cpd); strcat(buffer,"\n"); send(new_server_socket,buffer,BUFFER_SIZE,0); bzero(buffer,BUFFER_SIZE); length = recv(new_server_socket,buffer,BUFFER_SIZE,0); if (length < 0){ printf("Server Recieve Data Failed!\n"); exit(1); } fprintf(stderr,"got: %s in %d\n",buffer,getpid()); close(new_server_socket); exit(0); } else if(child_process_pid > 0) close(new_server_socket); } close(server_socket); return 0;}

client:

#include 
#include
#include
#include
#include
#include
#include
#define HELLO_WORLD_SERVER_PORT 6666#define BUFFER_SIZE 1024void talk_to_server(char ** argv){ struct sockaddr_in client_addr; bzero(&client_addr,sizeof(client_addr)); client_addr.sin_family = AF_INET; client_addr.sin_addr.s_addr = htons(INADDR_ANY); client_addr.sin_port = htons(0); int client_socket = socket(AF_INET,SOCK_STREAM,0); if( client_socket < 0){ printf("Create Socket Failed!\n"); exit(1); } if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr))){ printf("Client Bind Port Failed!\n"); exit(1); } struct sockaddr_in server_addr; bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family = AF_INET; if(inet_aton(argv[1],&server_addr.sin_addr) == 0) { printf("Server IP Address Error!\n"); exit(1); } server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT); socklen_t server_addr_length = sizeof(server_addr); if( connect( client_socket, (struct sockaddr*)&server_addr, server_addr_length) < 0 ) { printf("Can Not Connect To %s!\n",argv[1]); exit(1); } char buffer[BUFFER_SIZE]; bzero(buffer,BUFFER_SIZE); int length = recv( client_socket, buffer,BUFFER_SIZE,0); if(length < 0){ printf("Recieve Data From Server %s Failed!\n", argv[1]); exit(1); } printf("From Server %s :\t%s",argv[1],buffer); bzero(buffer,BUFFER_SIZE); char name[64]; gethostname(name,sizeof(name)); strcpy(buffer,name); send(client_socket,buffer,BUFFER_SIZE,0); close(client_socket);}int main(int argc, char **argv){ if (argc != 2){ printf("Usage: ./%s ServerIPAddress\n",argv[0]); exit(1); } int i=0; for(i=0; i<10000; i++){ talk_to_server(argv); sleep(10); } return 0;}

然后,用三个机器,一个跑server,两个跑client。先运行server,再分别跑两个client,结果如下:

为了方便观察,略作整理:

Server端运行结果:

./con-server.o Before Main Process listen.                    After Main Process listen.                    Before accept. In 676.                    After accept. In 676                            Child 678 born.            Before accept. In 676.                            got : post2.gao in 678            After accept. In 676.                                Child 679 born.        Before accept. In 676.                                got: post3.gao in 679.        After accept. In 676.                                    Child 680 born.    Before accept. In 676.                                    got: post2.gao in 680.    After accept. In 676.                                        Child. 681 born.Before accept. In 676.                                        got: post3.gao in 681 ......

两个client端运行结果:

./con-client.o  192.168.66.136                                        From Server 192.168.66.136:  Hello,World! From Server! 678                    From Server 192.168.66.136:  Hello,World! From Server! 680 ......

 

./con-client.o  192.168.66.136                                        From Server 192.168.66.136:  Hello,World! From Server! 679                    From Server 192.168.66.136:  Hello,World! From Server! 681 ......

这样就成为多个客户端请求Server端。

此外也可以发现,listen动作不阻塞,accept动作阻塞。

服务器端主进程每当捕获到一个客户端请求,就fork一个子进程,

由子进程用 new_server_socket来send 和 recv工作。

fork子进程后,工作完毕再消除的方法未必理想,今后有机会看看能否事先开一个进程池,来提升效率。

转载地址:http://dzutx.baihongyu.com/

你可能感兴趣的文章
Android Studio插件
查看>>
地图应用总结研究报告发布
查看>>
【转】 TechED2010与我(三) —— 初识云计算
查看>>
C语言第四次博客作业
查看>>
【ADO.NET】7、SQL高级封装
查看>>
三十分钟学完Vue
查看>>
[Contest20180405]抑制「超我」
查看>>
WPF 自定义TreeView控件样式,仿QQ联系人列表
查看>>
mongoDB 文档操作_增
查看>>
Lambda表达式之查询篇
查看>>
JavaScript正则表达式总结
查看>>
node环境下express路由,
查看>>
hdu 1754 I Hate It
查看>>
HelloWorld 模块
查看>>
神经网络-手写字体识别
查看>>
Javascript模拟继承(赠送.net吐槽一段)
查看>>
Problem D
查看>>
数据分析之异常值分析-箱线图
查看>>
会计的思考(31):真正的成本会计在制造部
查看>>
tornado+jsonrpc
查看>>