我们有一个使用live555库实现的流服务器。该服务器部署在CentOS实例上。
最近,我们想修改服务器套接字选项,以便它可以在重新启动进程后立即崩溃(崩溃或手动重新启动之后)。
我已经参考了手册页和少量Web链接,并在调用SO_REUSEADDR
之前设置了套接字选项(SO_REUSEPORT
和bind()
)。
int setupStreamSocket(UsageEnvironment& env,
Port port, Boolean makeNonBlocking) {
int newSocket = createSocket(SOCK_STREAM);
if (newSocket < 0) {
socketErr(env, "unable to create stream socket: ");
return newSocket;
}
int reuseFlag = 1;
fprintf(stderr,"reuseFlag : %d\n",reuseFlag);
if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
(const char*)&reuseFlag, sizeof reuseFlag) < 0) {
socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
closeSocket(newSocket);
return -1;
}
if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
(const char*)&reuseFlag, sizeof reuseFlag) < 0) {
socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
closeSocket(newSocket);
return -1;
}
int flag = 1;
setsockopt( newSocket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag) );
if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num());
int reuse_addr_val, reuse_port_val;
socklen_t reuse_addr_len = sizeof(reuse_addr_val);
socklen_t reuse_port_len = sizeof(reuse_port_val);
getsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr_val, &reuse_addr_len);
getsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT, &reuse_port_val, &reuse_port_len);
fprintf(stderr,"reuse_addr_val = %d, reuse_port_val = %d\n", reuse_addr_val, reuse_port_val);
if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
char tmpBuffer[100];
sprintf(tmpBuffer, "bind() error (port number: %d): ",
ntohs(port.num()));
socketErr(env, tmpBuffer);
closeSocket(newSocket);
return -1;
}
}
if (makeNonBlocking) {
if (!makeSocketNonBlocking(newSocket)) {
socketErr(env, "failed to make non-blocking: ");
closeSocket(newSocket);
return -1;
}
}
return newSocket;
}
如果我使用上述选项重新启动服务器,则此代码将按预期工作(即使套接字处于TIME_WAIT
状态也绑定到地址)。
如果我用上面的代码创建的构建替换了先前的构建(没有套接字选项),那么我注意到bind()
有时会因地址已在使用中而失败。
当bind()
失败时,端口/地址处于TIME_WAIT
状态。因此服务器应该能够将套接字绑定到该地址。
tcp 0 0 10.0.1.24:8554 10.0.1.89:27085 TIME_WAIT-
我的代码中的getsockopt()
将标志值(对应于SO_REUSEADDR
和SO_REUSEPORT
)打印为1。
reuse_addr_val = 1,reuse_port_val = 1
bind()错误(端口号:8554):地址已在使用中
所以我想知道为什么它只有几次失败。我是否错过了代码中的某些内容?还是这是预期的行为?