了解Unix/Linux的人都知道,一般而言,只会在服务器端的监听进程才会指定端口,那么客户端的进程是否也能够指定端口呢?
我们同样利用bind函数来为客户端的进程指定端口。
首先,我们运行一个不指定端口的客户端程序,看一下数据包传输的情况:
1.通过sudo tcpdump命令打开工具软件
2.执行客户端程序
3.观察数据包传输的情况
结果如下:
下面来说一下客户端进程指定端口号:
其实很简单,跟服务器端一样,我们通过调用bind函数来绑定端口号,我在自己的实验代码中加入了一下的语句:
struct sockaddr_in clientaddr;
memset( &clientaddr, 0, sizeof( clientaddr ));
clientaddr.sin_port = htons( 8000 );
bind( sockfd, ( struct sockaddr * )&clientaddr, sizeof( clientaddr )); //sockfd是socket函数的返回值
编译运行,仍然通过sudo tcpdump来查看数据包传输情况,如下图:
我们发现,客户端的端口果然改变了,是不是到此就成功了呢?我们执行完第一次client程序后,立刻执行第二次client程序,结果如下:
我们很神奇的发现,端口号并非是我们所指定的!
那么为什么第一次执行用的是我们指定的端口号,第二次就不是了呢,这就是因为我们上面提到过的TIME_WAIT这个状态造成的。我们通过查看端口状态,的确可以看到8000处于TIME_WAIT状态,所以它不能被分配给第二次执行的进程。只要等第一次执行完毕以后,等待端口恢复正常以后,再执行第二次,就可以看到我们想要的结果。
这里我对Linux的端口选择机制不是很了解,大胆推测一下,如果操作系统发现指定的端口不可用,那么就会任意分配一个给进程,不会产生任何错误报告(即使有,对程序员来说也是透明的)。