我有简单的TCP服务器程序。在我使用CTRL+C
关闭它并在某些情况下再次重新启动后,telnet客户端报告我"connection refused"
。为什么不总是这样,但在某些情况下呢?命令ps
没有显示我的程序。
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>
void printHex(char *bts);
int main() {
char str[100];
int listen_fd, comm_fd;
struct sockaddr_in servaddr;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
bzero( &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(22000);
printf("binding\n");
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
printf("listening\n");
listen(listen_fd, 10);
printf("accepting\n");
comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
printf("accep done\n");
int cn = 0;
while(1) {
bzero(str, 100);
printf("will read\n");
int br = read(comm_fd, str, 100);
printf("read done\n");
if (br > 0) {
printHex(str);
} else if (br <= 0) {
comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
printf("accep done\n");
}
printf("error %d \n", br);
}
}
void printHex(char *bts) {
char *s = bts;
int i = 0;
do {
printf("%02X ", (unsigned char) *bts);
} while (*++bts !=0);
printf("%s\n",s);
}
答案 0 :(得分:1)
您应该检查系统调用的所有返回值:
int res;
res = bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (res == -1)
// handle error
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listed_fd == -1)
// handle error
您很可能会发现您的代码在bind
系统调用中失败,这意味着您无法在相同的IP地址,协议和端口上重用套接字。您可以使用setsockopt
调用
// allow to rebind
int reuseaddr_on = 1;
res = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
&reuseaddr_on, sizeof(reuseaddr_on));
if (res < 0)
{
stderr("Setting of SO_REUSEADDR on server's"
"socket failed");
}
完成后,您还应该关闭套接字。
while(1)
{
// your loop
}
res = close(comm_fd);
if (res == -1)
// handle error
正如Linux程序员手册在致电近距离呼叫的网页上所说:
注意
不检查close()的返回值是一个常见但严重的编程错误。很有可能 先前write(2)操作的错误首先在最后的close()处报告。关闭文件时不检查返回值可能会导致静默 失去了 数据
答案 1 :(得分:0)
始终检查系统调用的返回值。 在这种情况下,
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
与EADDRINUSE
失败,因为在绑定之前没有在套接字上设置SO_REUSEADDR
。
答案 2 :(得分:0)
当您执行CTRL-C并重新启动时,绑定是否成功?
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
您需要检查bind call
的状态。很可能由于连接已在服务器中移至TIME_WAIT
状态而失败。从此,客户端出现“连接被拒绝”的错误。
在bind
之后立即运行服务器时,CTRL-C
要成功,请使用套接字选项中的SO_REUSEADDR
。只要没有另一个程序绑定到端口,这个bind
就会成功。