前面我们已经将了tcp/udp的基本知识,还说了并发服务器与迭代服务器的区别,我们大致了解大多数tcp服务器是并发的,大多数udp服务器是迭代的 ,即我们在进行数据传送的时候,往往使用服务器与客户但之间无连接的udp报文,但是在用户需要上传下载文件时,就会在客户端和服务器之间建立一条tcp连接,进行文件的传送
那么我们下面就来实现一个简单的tcp服务器。
我们首先看一下tcp客户端与服务端的编程模型和流程。
此模型不仅适合迭代服务器,也适合并发服务器,不管服务器是并发的还是迭代的,两者实现流程类似,只不过并发服务器接收客户请求(accept)后会fork子进程,由子进程处理客户端的请求,而迭代服务器则会一直处理客户端的请求直至请求结束,因此在这期间不会再响应其他客户端的请求。
(1)server 服务器端编程流程
tcp服务器端编程流程如下:
① 创建套接字socket;
② 绑定套接字bind;
③ 设置套接字为监听模式,进入被动接受连接状态listen;
④ 接受请求,建立连接accpet;
⑤ 读写数据read/write;
⑥ 终止连接close。
(2) client客户端编程流程
tcp客户端编程流程如下:
② 与远程服务器建立连接connect;
③ 读写数据read/write;
④ 终止连接close。
3) tcp服务器三种异常情况
tcp服务器有三种异常情况,分别为服务器主机崩溃、服务器主机崩溃后重启、服务器主机关机。
服务器主机崩溃
在服务器主机崩溃的情况下,已有的tcp网络连接上发不出任何东西。
此时客户端发出数据后,会一直阻塞在套接字的读取响应。但是由于服务器主机已崩溃,tcp客户端会持续重传数据分节,试图从服务器接收一个ack[一般重传12次(源自berkeley的实现)]后,客户tcp最终选择放弃,返回给应用经常一个etimedout错误;或者是因为中间路由器判定服务器主机不可达,则返回一个目的地不可达的icmp消息响应,其错误代码为ehostunreach或enetunreach。
简单来说,客户端会一直阻塞与read调用,然后一直重传,直到最后超时,客户最终会发现服务器主机已崩溃或主机不可达,然后返回一个状态码,但是这个过程可能是很长就的,解决的方法就是自己写一个read函数然后设置超时,或者加一个so_keepalive选项,也可以通过设置套接字选项可以更改tcp持续重传等待的超时时间。
服务器主机崩溃后重启
在服务器主机崩溃后重启的情况下,如果客户在主机崩溃重启前不主动发送数据,那么客户是不会知道服务器已崩溃。
在服务器重启后,客户向服务器发送一个数据分节;由于服务器重启后丢失了以前的连接信息(尽管在服务端口上有进程监听,但连接套接字所在的端口无进程等待),因此导致服务器主机的tcp响应rst;而客户由于之前未收到服务器的响应数据,页阻塞于read调用,当客户端收到这个rst之后便返回错误econnreset。
如果客户对服务器的崩溃情况很关心,即使客户不主动发送数据也这样,这需要进行相关设置(如设置套接口选项so_keepalive或某些客户/服务器心跳函数)。
服务器主机关机
这里一般指的是正常关机,因为unix系统关机时,会发送sigterm和sigkill信号,sigtrem可能忽略,但是sigkill信号不能忽略,于是服务器将由sigkill终止,
当服务器主机关机的情况下,由于init进程给所有运行的进程发信号sigterm,这时服务器程序可以捕获该信号,并在信号处理程序中正常关闭网络连接。如果服务器程序忽略了sigterm信号,则init进程会等待一段固定的时间(通常是5s~20s),然后给所有还在运行的程序发信号sigkill。服务器将由信号sigkill终止,其终止时,所有打开的描述字被关闭,这导致向客户发送fin分节,客户收到fin分节后,能推断出服务器将终止服务。
我们下面将实现一个迭代类型的简单tcp服务器与客户端,实现客户端从服务器上传/下载文件(我们的程序中主要是上传)。
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
由于tcp和udp在实现流程上有很多异曲同工之处,因此我们后面的拓展优化将主要针对tcp套接字程序,我们在下一篇开始udp的套接字编程详解,理解了tcp不同的实现思想之后稍加修改即可。。。。
转载:http://blog.csdn.net/gatieme/article/details/46357249