6.1 socket

  一般情况下,服务器的长连接和短连接不是服务器说了算,而是客户端说了算。因为服务器是给别人提供业务的,一旦连接建立起来之后,服务器端不会主动把连接给close掉。

  客户端发送一笔业务,没有关闭连接,然后又发送一笔业务,还是没有关闭连接,这个连接叫长连接,就是说客户端和服务器端建立完业务以后,就不断开连接了。建立连接需要很长时间,优化服务器一般就是优化连接,

  客户端每做一次通信就连接一下服务器,也就是每做一次通信就建立一个连接,然后断掉。这叫短连接。

短连接的示例程序如下:

 1 #include <sys/types.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <stdio.h>
 5 #include <string.h>
 6 #include <errno.h>
 7 #include <arpa/inet.h>
 8 #include <sys/socket.h>
 9 #include <netinet/in.h>
10 #include <sys/socket.h>
11 #include <netinet/ip.h> /* superset of previous */
12 
13 int main()
14 {
15     int i = 0;
16     for(i = 0; i < 10; i++)
17     {
18         int sockfd = 0;
19         sockfd = socket(AF_INET, SOCK_STREAM, 0);
20     
21         struct sockaddr_in addr;
22         addr.sin_family = AF_INET;
23         addr.sin_port = htons(8001);
24         inet_aton("192.168.31.128", &addr.sin_addr);
25         //addr.sin_addr.s_addr = inet_addr("192.168.31.128");
26     
27         if( connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 )
28         {
29             perror("connect error");
30             exit(0);
31         }
32     
33         char recvbuf[1024] = {0};
34         char sendbuf[1024] = {0};
35     
36         sprintf(sendbuf, "i : %d\n", i);
37         
38         write(sockfd, sendbuf, strlen(sendbuf));
39     
40         read(sockfd, recvbuf, sizeof(recvbuf));
41     
42         fputs(recvbuf, stdout);
43         memset(recvbuf, 0, sizeof(recvbuf));
44         memset(sendbuf, 0, sizeof(sendbuf));
45     
46         close(sockfd);
47     }
48     
49     return 0;
50 }

每发一次报文就连接一次,一共进行了10次连接,执行结果如下:

如果需要和服务器频繁的交互,长连接比较好。如果长时间不发一次报文,则短连接好。

客户端和服务器建立连接后,假如20分钟不动,特别是在公网上,则这个连接有可能被TCP IP协议重置,再发报文就是错误码。20分钟不动就重置连接这种操作可以在服务器提前设置。

p2p聊天程序,模型如下:

客户端的父进程从键盘接收数据,然后发送给服务器,服务器父进程接收数据并打印。 服务器子进程从键盘接收数据,然后发送给客户端,客户端的子进程接收数据并打印。

服务器端程序如下:

  1 #include <sys/types.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <stdio.h>
  5 #include <string.h>
  6 #include <errno.h>
  7 #include <arpa/inet.h>
  8 #include <sys/socket.h>
  9 #include <netinet/in.h>
 10 #include <sys/socket.h>
 11 #include <netinet/ip.h> /* superset of previous */
 12 
 13 
 14 int main()
 15 {
 16     int sockfd = 0;
 17     sockfd = socket(AF_INET, SOCK_STREAM, 0);
 18     
 19     if(sockfd == -1)
 20     {
 21         perror("socket error");
 22         exit(0);
 23     }
 24     
 25     struct sockaddr_in addr;
 26     addr.sin_family = AF_INET;
 27     addr.sin_port = htons(8001);
 28     inet_aton("192.168.31.128", &addr.sin_addr);
 29     //addr.sin_addr.s_addr = inet_addr("192.168.6.249");
 30     //addr.sin_addr.s_addr = INADDR_ANY;
 31     
 32     int optval = 1;
 33     if( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
 34     {
 35         perror("setsockopt error");
 36         exit(0);    
 37     }
 38     
 39     if( bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
 40     {
 41         perror("bind error");
 42         exit(0);
 43     }
 44     
 45     if(listen(sockfd, SOMAXCONN) < 0)
 46     {
 47         perror("listen error");
 48         exit(0);
 49     }
 50     
 51     struct sockaddr_in peeraddr;
 52     socklen_t peerlen;
 53     
 54     int conn = 0;
 55     
 56     char *p = NULL;
 57     int peerport = 0;
 58     p = inet_ntoa(peeraddr.sin_addr);
 59     peerport = ntohs(peeraddr.sin_port);
 60     
 61     char recvbuf[1024] = {0};
 62     int ret = 0;
 63 
 64     conn = accept(sockfd, (struct sockaddr *)&peeraddr, &peerlen);
 65     if(conn == -1)
 66     {
 67         perror("accept error");
 68         exit(0);
 69     }
 70     
 71     pid_t pid = 0;
 72     pid = fork();
 73     
 74     if(pid > 0)
 75     {
 76         printf("peeraddr = %s\n peerport = %d\n", p, peerport);
 77         char recvbuf[1024] = {0};
 78         
 79         while(1)
 80         {
 81             ret = read(conn, recvbuf, sizeof(recvbuf));
 82     
 83             if(ret == 0)
 84             {
 85                 printf("peer closed \n");
 86                 exit(0);
 87             }
 88             else if(ret < 0)
 89             {
 90                 perror("read error");
 91                 exit(0);
 92             }
 93             
 94             printf("recvive from client : %s", recvbuf);
 95             //fputs(recvbuf, stdout);
 96     
 97         }
 98     }
 99     else if(pid == 0)
100     {
101         close(sockfd);
102         char sendbuf[1024] = {0};
103         
104         while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
105         {
106             write(conn, sendbuf, strlen(sendbuf));
107             memset(sendbuf, 0, sizeof(sendbuf));
108         }
109         close(conn);
110     }
111     else
112     {
113         perror("fork error");
114         close(conn);
115         close(sockfd);
116         exit(0);
117     }
118     
119     
120     return 0;
121 }

客户端程序如下:

 1 #include <sys/types.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <stdio.h>
 5 #include <string.h>
 6 #include <errno.h>
 7 #include <arpa/inet.h>
 8 #include <sys/socket.h>
 9 #include <netinet/in.h>
10 #include <sys/socket.h>
11 #include <netinet/ip.h> /* superset of previous */
12 
13 int main()
14 {
15     int sockfd = 0;
16     sockfd = socket(AF_INET, SOCK_STREAM, 0);
17     
18     struct sockaddr_in addr;
19     addr.sin_family = AF_INET;
20     addr.sin_port = htons(8001);
21     inet_aton("192.168.31.128", &addr.sin_addr);
22     //addr.sin_addr.s_addr = inet_addr("192.168.31.128");
23     
24     if( connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 )
25     {
26         perror("connect error");
27         exit(0);
28     }
29     
30     int pid = fork();
31     
32     if(pid > 0)
33     {
34         char sendbuf[1024] = {0};
35         while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
36         {
37             write(sockfd, sendbuf, strlen(sendbuf));
38             memset(sendbuf, 0, sizeof(sendbuf));
39         }
40         close(sockfd);
41     }
42     else if(pid == 0)
43     {
44         char recvbuf[1024] = {0};
45         while(1)
46         {
47             read(sockfd, recvbuf, sizeof(recvbuf));
48             printf("recvive from server : %s", recvbuf);
49             //fputs(recvbuf, stdout);
50             memset(recvbuf, 0, sizeof(recvbuf));
51         }
52     }
53     else
54     {
55         perror("fork error");
56         exit(0);
57     }
58     
59     return 0;
60 }

执行结果如下:

TCP IP协议流协议,服务器读到\0时就知道客户端已经断开连接了。 什么时候客户端会发送'\0'呢? 就是当客户端关闭套接字时,TCP IP协议栈会发送一个FIN,这时候服务器端如果继续read的话,就会读到一个'\0' 。当客户端按下ctrl+c时,TCP IP协议栈就会发出FIN了,这时服务器端就能检测到客户端关闭了,如下所示:

猜你喜欢

转载自www.cnblogs.com/wanmeishenghuo/p/9386651.html
6.1