socket编程之bind函数
bind 函数:关联地址和套接字
定义:
1 |
|
返回值:若成功,返回 0;若出错,返回 -1.
使用 bind 时遇到的错误
在练习 UNP 代码 daytimetcpsrv.c 时遇到两个问题:
Permission denied
这是因为地址中的端口号必须不小于 1024,除非该进程具有相应的特权(即 root 用户)。
Address already in use
这个问题有时会让人很疑问,明明已经结束了使用对应端口的进程,端口应该不是
in use
的啊,但却无法再次调用 bind 函数来绑定该端口到一个套接字端点(bind 函数返回EADDRINUSE
)。其实这是由 TCP 套接字状态TIME_WAIT
引起的,该状态在套接字关闭后约保留 2 到 4 分钟,因此无法再次绑定刚刚使用的端口。在TIME_WAIT
状态退出之后,套接字被删除,该地址才能被重新绑定而不出问题。可以通过 netstat -ant 来查看这个端口还处于
TIME_WAIT
状态:等待
TIME_WAIT
结束可能是令人恼火的一件事,特别是如果您正在开发一个套接字服务器,就需要停止服务器来做一些改动,然后重启。幸运的是,有方法可以避开TIME_WAIT
状态。可以给套接字应用SO_REUSEADDR
套接字选项,以便端口可以马上重用。对于 daytimetcpsrv.c,可以加上以下代码:
1
2
3
4
5
6
7int reuse = 1;
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("setsockopet error\n");
return -1;
}重新编译运行。
关于 TIME_WAIT 状态
TCP 设计中之所以要让一个旧的连接处于 TIME_WAIT 状态是因为要防止旧连接的老的重复分组出现在新连接中。拿 UNP 上面的例子来说:
假设在 12.106.32.245 的端口 1500 和 206.168.112.219 的端口 21 之间有一个 TCP 连接。当我们关闭这个连接后,很快又重新建立一条相同 IP 和端口的 TCP 连接。在这种情况下,假如旧连接在网络中还存在没有被丢弃的重复分组,而且重复分组又出现在了新连接中了,TCP 将无法正确处理这个分组。为了防止这种情况的发生,TCP 将刚关闭的连接置于 TIME_WAIT 状态,不允许给处于该状态的连接启动新的化身,持续时间是 2MSL,如此将能保证该连接的老的重复分组都已在网络中消逝。
注:是主动执行关闭 TCP 连接的那端将处于 TIME_WAIT 状态。