Unix网络编程—为客户端进程指定端口

了解Unix/Linux的人都知道,一般而言,只会在服务器端的监听进程才会指定端口,那么客户端的进程是否也能够指定端口呢?

我们同样利用bind函数来为客户端的进程指定端口。

首先,我们运行一个不指定端口的客户端程序,看一下数据包传输的情况:

1.通过sudo tcpdump命令打开工具软件

2.执行客户端程序

3.观察数据包传输的情况

结果如下:



关于数据包的内容我就不解释了,我们只要知道,master是客户端,39400是客户端进程的端口,下面重复一次上面的操作,结果如下:



我们发现,前后两次执行的客户端进程所用的端口不一样了,虽然说端口由操作系统来指定,可是为什么要换一个呢?
我们通过netstat -an命令来查看端口状态,如下图:
Unix网络编程—为客户端进程指定端口_第1张图片

可以看到,当执行完客户端程序后的一段时间内(TCP连接还没完全关闭),连接处于TIME_WAIT(这个时间实际上是2MSL),也就是说在这段时间内,该端口还不能被其他进程所使用,所以操作系统为了避免这种情况,会选择一个不同的端口号分配给进程。


下面来说一下客户端进程指定端口号:

其实很简单,跟服务器端一样,我们通过调用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的端口选择机制不是很了解,大胆推测一下,如果操作系统发现指定的端口不可用,那么就会任意分配一个给进程,不会产生任何错误报告(即使有,对程序员来说也是透明的)。

你可能感兴趣的:(网络编程)