代码改变世界

Linux TCP server系列(1)-简单TCP服务器+多进程处理客户请求

2011-09-15 09:53  Aga.J  阅读(8723)  评论(1编辑  收藏  举报

目标:
  完成一个精简TCP服务器,可接收来自多个用户的请求,并返回结果。


思路:
  (1)服务器
      C++ TCP服务器的实现主要由以下几个函数来完成:
        a)socket
     创建服务器监听套接字
  b)bind
     绑定服务器监听信息到套接字上
  c)listen
     开始监听,接收客户端的TCP连接
  d)accept
     从listen所维护的队列中取出一条已连接的TCP,返回该连接的socket描述字
        e)服务器客户端在连接socket描述字上进行消息通信
  f) close
     关闭打开着的套接字
      为了更好的服务多个发起请求的客户端,在e步骤上,我们使用fork以派生子进程来独立处理每个客户端的请求。
      if( (childpid=fork())==0)
     {
      close(listenfd);         //从父进程复制下来的监听socket描述符要关闭。
      //communication(connfd);
      exit(0);
     }
(2)客户端
    客户端的实现主要由以下函数完成:
     a)socket
        创建客户端连接套接字
    b)connect
    向指定服务器发起连接请求
     c)服务器客户端在连接socket描述字上进行消息通信
     d)close
        关闭打开着的套接字


实现:

server.cpp
 1 #include<sys/types.h>
2 #include<sys/socket.h>
3 #include<strings.h>
4 #include<arpa/inet.h>
5 #include<unistd.h>
6 #include<stdlib.h>
7 #include<stdio.h>
8 #include<string.h>
9 #include<errno.h>
10 #include<signal.h>
11 #include<sys/wait.h>
12
13 #define LISTEN_PORT 84
14 void str_echo(int sockfd)
15 {
16 ssize_t n;
17 char line[512];
18
19 printf("ready to read\n");
20 while( (n=read(sockfd,line,512))>0 )
21 {
22 line[n]='\0';
23 printf("Client: %s\n",line);
24 bzero(&line,sizeof(line));
25 }
26 printf("end read\n");
27 }
28
29 int main(int argc, char **argv)
30 {
31 int listenfd, connfd;
32 pid_t childpid;
33 socklen_t chilen;
34
35 struct sockaddr_in chiaddr,servaddr;
36
37 listenfd=socket(AF_INET,SOCK_STREAM,0);
38 if(listenfd==-1)
39 {
40 printf("socket established error: %s\n",(char*)strerror(errno)); return -1;
41 }
42
43 bzero(&servaddr,sizeof(servaddr));
44 servaddr.sin_family=AF_INET;
45 servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
46 servaddr.sin_port=htons(LISTEN_PORT);
47
48 int bindc=bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
49 if(bindc==-1)
50 {
51 printf("bind error: %s\n",strerror(errno)); return -1;
52 }
53
54 listen(listenfd,5);
55 for(;;)
56 {
57 chilen=sizeof(chiaddr);
58
59 connfd=accept(listenfd,(struct sockaddr*)&chiaddr,&chilen);
60 if(connfd==-1)
61 { printf("accept client error: %s\n",strerror(errno)); return -1; }
62 else
63 printf("client connected\n");
64
65 if((childpid=fork())==0)
66 {
67 close(listenfd);
68 printf("client from %s\n",inet_ntoa(chiaddr.sin_addr));
69 str_echo(connfd);
70 exit(0);
71 }
72 else if (childpid<0)
73 printf("fork error: %s\n",strerror(errno));
74 close(connfd);
75 }
76 }

client.cpp

 1 #include<sys/types.h>
2 #include<stdlib.h>
3 #include<stdio.h>
4 #include<unistd.h>
5 #include<sys/socket.h>
6 #include<strings.h>
7 #include<string.h>
8 #include<arpa/inet.h>
9 #include<errno.h>
10
11 #define SERVER_PORT 84
12 void str_cli(char *data,int sockfd)
13 {
14 char recv[512];
15
16 int wc=write(sockfd,data,strlen(data));
17
18 exit(0);
19 }
20 int main(int argc, char **argv)
21 {
22 int sockfd;
23 struct sockaddr_in servaddr;
24
25 if(argc!=3)
26 return -1;
27
28 sockfd=socket(AF_INET,SOCK_STREAM,0);
29 if(sockfd==-1)
30 {
31 printf("socket established error: %s\n",(char*)strerror(errno)); return -1;
32 }
33
34 bzero(&servaddr,sizeof(servaddr));
35 servaddr.sin_family=AF_INET;
36 servaddr.sin_port=htons(SERVER_PORT);
37 inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
38
39 printf("client try to connect\n");
40 int conRes=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
41 if(conRes==-1)
42 {
43 printf("connect error: %s\n",strerror(errno)); return -1;
44 }
45
46 str_cli(argv[2],sockfd);
47
48 exit(0);
49 }

 

分析:
   最简单的服务器仅能完成基本的通信,并没有考虑其他边界或者异常情况,同时,采用子进程处理客户端连接,一旦子进程数量增多,并且子进程需要长时间的运行,那么服务器性能将严重下降。