加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

UNIX网络编程:TCP回射服务器/客户端程序

发布时间:2016-09-26 16:12:45 所属栏目:Unix 来源:站长网
导读:副标题#e# 下面通过最简单的客户端/服务器程序的实例来学习socket API。 serv.c 程序的功能是从客户端读取字符然后直接回射回去: #includestdio.h #includesys/types.h #includesys/socket.h #includeunistd.h #includestdlib.h #includeerrno.h #includea

先编译运行服务器:

huangcheng@ubuntu:~$./serv

然后在另一个终端里用netstat命令查看:

huangcheng@ubuntu:~$ netstat -anp | grep 5188  
(并非所有进程都能被检测到,所有非本用户的进程信息将不会显示,如果想看到所有信息,则必须切换到 root 用户)  
tcp        0      0 0.0.0.0:5188            0.0.0.0:*               LISTEN      2998/serv

可以看到server程序监听5188端口,IP地址还没确定下来。现在编译运行客户端:

huangcheng@ubuntu:~$ ./cli

回到server所在的终端,看看server的输出:

huangcheng@ubuntu:~$ ./serv  
recv connect ip=127.0.0.1 port=42107

可见客户端的端口号是自动分配的。再次netstat 一下:

huangcheng@ubuntu:~$ netstat -anp | grep 5188  
(并非所有进程都能被检测到,所有非本用户的进程信息将不会显示,如果想看到所有信息,则必须切换到 root 用户)  
tcp        0      0 0.0.0.0:5188            0.0.0.0:*               LISTEN      2998/serv     
tcp        0      0 127.0.0.1:5188          127.0.0.1:42107         ESTABLISHED 2998/serv     
tcp        0      0 127.0.0.1:42107         127.0.0.1:5188          ESTABLISHED 3198/cli

应用程序中的一个socket文件描述符对应一个socket pair,也就是源地址:源端口号和目的地址:目的端口号,也对应一个TCP连接。

上面第一行即serv.c 中的listenfd;第二行即serv.c 中的sock; 第三行即cli 中的conn。2998和3198分别是进程id。

现在来做个测试,先serv.c中的把33~35行的代码注释掉。

首先启动server,然后启动client,然后用Ctrl-C使server终止,这时马上再运行server,结果是:

huangcheng@ubuntu:~$ ./serv  
bind error: Address already in use

这是因为,虽然server的应用程序终止了,但TCP协议层的连接并没有完全断开,因此不能再次监听同样的server端口。我们用netstat命令查看一下:

huangcheng@ubuntu:~$ netstat -anp | grep 5188  
(并非所有进程都能被检测到,所有非本用户的进程信息将不会显示,如果想看到所有信息,则必须切换           到 root 用户)  
tcp        0      0 127.0.0.1:5188          127.0.0.1:42108         FIN_WAIT2   -                        
tcp        1      0 127.0.0.1:42108         127.0.0.1:5188          CLOSE_WAIT  3260/cli

server终止时,socket描述符会自动关闭并发FIN段给client,client收到FIN后处于CLOSE_WAIT状态,但是client并没有终止,也没有关闭socket描述符,因此不会发FIN给server,因此server的TCP连接处于FIN_WAIT2状态。

现在用Ctrl-C把client也终止掉,再观察现象:

huangcheng@ubuntu:~$ netstat -anp | grep 5188  
(并非所有进程都能被检测到,所有非本用户的进程信息将不会显示,如果想看到所有信息,则必须切换到 root 用户)  
tcp        0      0 127.0.0.1:5188          127.0.0.1:42108         TIME_WAIT   -
huangcheng@ubuntu:~$ ./serv  
bind error: Address already in use

client终止时自动关闭socket描述符,server的TCP连接收到client发的FIN段后处于TIME_WAIT状态。TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL(maximumsegment lifetime)的时间后才能回到CLOSED状态,需要有MSL 时间的主要原因是在这段时间内如果最后一个ack段没有发送给对方,则可以重新发送。因为我们先Ctrl-C终止了server,所以server是主动关闭连接的一方,在TIME_WAIT期间仍然不能再次监听同样的server端口。MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同,在Linux上一般经过半分钟后就可以再次启动server了。至于为什么要规定TIME_WAIT的时间请大家参考UNP 2.7节。

在server的TCP连接没有完全断开之前不允许重新监听是不合理的,因为,TCP连接没有完全断开指的是connfd(127.0.0.1:5188)没有完全断开,而我们重新监听的是listenfd(0.0.0.0:5188),虽然是占用同一个端口,但IP地址不同,connfd对应的是与某个客户端通讯的一个具体的IP地址,而listenfd对应的是wildcard address。解决这个问题的方法是使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1,表示允许创建端口号相同但IP地址不同的多个socket描述符。将原来注释的33~35行代码打开,问题解决。

先运行服务器,在运行客户端:

huangcheng@ubuntu:~$ ./serv  
recv connect ip=127.0.0.1 port=42107  
host 127.0.0.1:5188  
huangcheng  
ctt
huangcheng@ubuntu:~$ ./cli  
host 127.0.0.1:42107  
huangcheng  
huangcheng  
ctt  
ctt

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读