10 July 2017
 1: #include <stdio.h>
 2: #include <arpa/inet.h>
 3: #include <errno.h>
 4: #include <stdlib.h>
 5: #include <string.h>
 6: #include <unistd.h>
 7: 
 8: int main(int argc, char *argv[]) {
 9:     const int MAXLINE = 4096 + 1;
10:     char buf[MAXLINE];
11: 
12:     int port = 8888;
13:     if (argc == 2) {
14:         port = atoi(argv[1]);
15:     }
16: 
17:     int                server_fd;
18:     struct sockaddr_in server_addr;
19: 
20:     server_fd = socket(AF_INET, SOCK_STREAM, 0);
21:     memset(&server_addr, 0, sizeof(server_addr));
22:     server_addr.sin_family = AF_INET;
23:     server_addr.sin_port   = htons(port);
24:     inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
25: 
26:     int connect_res;
27:     while (1) {
28:         connect_res = connect(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));
29:         if (connect_res == 0) {
30:             printf("connected\n");
31:             break;
32:         } else {
33:             printf("reconnected\n");
34:         }
35:     }
36: 
37: 
38:     int nread_from_stdin;
39:     int nread_from_server;
40:     int nwrite;
41: 
42:     while (1) {
43:         nread_from_stdin = read(STDIN_FILENO, buf, MAXLINE);
44:         if (nread_from_stdin == 0) {
45:             printf("quit\n");
46:             break;
47:         }
48: 
49:         nwrite = write(server_fd, buf, nread_from_stdin);
50:         if (nwrite != nread_from_stdin) {
51:             fprintf(stderr, "write error\n");
52:             exit(-1);
53:         }
54: 
55:         nread_from_server = read(server_fd, buf, MAXLINE);
56:         write(STDOUT_FILENO, "read from server:", strlen("read from server:"));
57:         write(STDOUT_FILENO, buf, nread_from_server);
58:     }
59: 
60:     close(server_fd);
61: 
62:     return 0;
63: }

因为 client 的端口是随机的,这个随机值是由 /proc/sys/net/ipv4/ip_local_port_range 决定,上面的代码中,我们指定了 server 的 端口号为 8888

设置 服务器的 随机端口号为 8000 到 9000 这个范围

➜ echo '8000\t9000' > /proc/sys/net/ipv4/ip_local_port_range
➜ cat /proc/sys/net/ipv4/ip_local_port_range
8000    9000

当 client 的随机端口为 8888 的时候,就会 connect 上自己


自连接出现的问题:

  • client 的随机端口占用了 server 的端口

解决自连接的问题:

  • server 的端口避免在 ip_local_port_range 这个范围内
  • 判断连接成功的时候,获取一下 对端的 peer_addr,如果 local_addr==peer_addr 就是自连接,可以直接 close

相关阅读