-
Notifications
You must be signed in to change notification settings - Fork 0
/
accept_ECONNABORTED.c
171 lines (150 loc) · 3.46 KB
/
accept_ECONNABORTED.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#define EXIT(msg) do{ \
perror(msg); \
exit(-1); \
}while(0)
// SIGCHLD的信号处理
void sighandler(int signo)
{
if(signo == SIGCHLD)
{
pid_t pid;
// 一定要死循环
while(1)
{
// waitpid设置为WNOGANG, 非阻塞
if((pid = waitpid(-1, NULL, WNOHANG)) <= 0)
break;
printf("child %d terminated\n", pid);
}
}
}
// socket
int Socket(int protocol)
{
int sockfd;
if((sockfd = socket(AF_INET, SOCK_STREAM, protocol)) < 0)
EXIT("socket");
return sockfd;
}
// bind
int Bind(int sockfd, int port, const char *addr)
{
struct sockaddr_in sockaddr;
sockaddr.sin_addr.s_addr = inet_addr(addr);
sockaddr.sin_port = htons(port);
sockaddr.sin_family = AF_INET;
if(bind(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0)
{
if(errno == EADDRINUSE)
fprintf(stderr, "addr %s erro\n", inet_ntoa(sockaddr.sin_addr));
else if(errno == EINVAL)
fprintf(stderr, "port %d error\n", ntohs(sockaddr.sin_port));
EXIT("bind");
}
return 0;
}
// connect
int Connect(int sockfd, int port, const char *addr)
{
struct sockaddr_in sockaddr;
sockaddr.sin_port = htons(port);
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr(addr);
if(connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0)
EXIT("connect");
return 0;
}
// 服务端
int service(int port, const char *ser_addr)
{
int sockfd, clientfd;
sockfd = Socket(0);
Bind(sockfd, port, ser_addr);
listen(sockfd, 1);
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
sleep(5);
char buf[1024];
int n;
pid_t pid;
while(1)
{
clientfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
// accept被信号打断后重新运行
if(clientfd < 0)
{
if(errno == EINTR){
continue;
}
// 改错误依赖操作系统, 至少我的就没有收到
else if(errno == ECONNABORTED)
fprintf(stderr, "peer close\n");
else
EXIT("accept");
}
if((pid = fork()) < 0)
EXIT("fork");
else if(0 == pid)
{
close(sockfd);
while(1)
{
n = recv(clientfd, buf, sizeof(buf), 0);
if(0 == n)
break;
send(clientfd, buf, n, 0);
}
close(clientfd);
exit(0);
}
close(clientfd);
}
close(sockfd);
return 0;
}
// 客户端
int client(int port, const char *cli_addr)
{
int sockfd;
sockfd = Socket(0);
// 设置套接字选项
struct linger lig;
lig.l_onoff = 1;
lig.l_linger = 0;
// 客户端在 close 的时候不是发送 FIN,而是 RST.
if(setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (void *)&lig, sizeof(lig)) != 0)
EXIT("setsockopt");
// 连接后直接关闭
Connect(sockfd, port, cli_addr);
close(sockfd);
return 0;
}
// 输入 1(服务端)或者2(客户端) 端口号 本机IP地址
int main(int argc, char *argv[])
{
if(argc != 4)
exit(-1);
struct sigaction action;
action.sa_handler = sighandler;
action.sa_flags = 0;
sigemptyset(&action.sa_mask);
if(sigaction(SIGCHLD, &action, NULL) != 0)
EXIT("sig_atomict");
int i = atoi(argv[1]);
if(i == 1)
service(atoi(argv[2]), argv[3]);
if(2 == i)
client(atoi(argv[2]), argv[3]);
exit(EXIT_SUCCESS);
}