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

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

修改后的代码如下:

server :


#include<netinet/in.h> #include<sys/types.h> #include<sys/socket.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/signal.h> #include<sys/wait.h>  #define HELLO_WORLD_SERVER_PORT    6666 #define LENGTH_OF_LISTEN_QUEUE 20 #define BUFFER_SIZE 1024  void 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 <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define HELLO_WORLD_SERVER_PORT 6666
#define BUFFER_SIZE 1024

void 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子进程后,工作完毕再消除的方法未必理想,今后有机会看看能否事先开一个进程池,来提升效率。