C:带超时的非阻塞套接字:如何检查是否已发出连接请求?
C : non blocking sockets with timeout : how to check if connection request was made?
我想要一台服务器一次连接到一个客户端,在连接到给定客户端时忽略连接请求。
我也想避免服务器在侦听第一个客户端时被锁定,这样程序就可以干净地终止。
显然,可以使套接字成为非阻塞的:
http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#blocking
我相应地创建了我的套接字(为清楚起见删除了错误管理代码)
int sockfd;
struct sockaddr_in self;
sockfd = socket(AF_INET, SOCK_STREAM, 0));
fcntl(sockfd, F_SETFL, O_NONBLOCK); // making this socket non blocking
bzero(&self, sizeof(self));
self.sin_family = AF_INET;
self.sin_port = htons(port);
self.sin_addr.s_addr = inet_addr("127.0.0.1"); // allowing connection from localhost only.
bind(sockfd, (struct sockaddr*)&self, sizeof(self));
从那时起,我不确定如何管理超时。以下代码不起作用,但给出了我想要实现的想法。
int client_found = 0;
while ( no_stop_signal && client_found==0 ) {
listen(sockfd,1);
if ( ** something that tells me nobody was requesting connection ** ) {
usleep(10);
} else {
client_found = 1;
}
}
到目前为止我找到的任何解决方案都关注比我的情况更复杂的情况(即一旦找到客户就不会忽略客户)并且看起来不必要地复杂。
编辑(接受答案后):
根据已接受的答案,这里是我附带的代码:
static inline int wait_for_client_to_connect(int sockfd, int* server_run){
int client_found = 0;
int clientfd = 0;
struct sockaddr_in client_addr;
int addrlen=sizeof(client_addr);
if ( listen(sockfd,1) != 0 ) return -1;
while ( client_found==0 && *server_run==1 ) {
clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);
if ( clientfd < 0 ) {
clientfd = 0;
if (errno==EAGAIN || errno==EWOULDBLOCK) usleep(10); // nobody connected, wait for request
else return -1; // something wrong, send error
} else { // client found, configuring socket and exit
client_found=1;
int nodelay_flag = 1;
setsockopt(clientfd, IPPROTO_TCP, TCP_NODELAY, (void*) &nodelay_flag, sizeof(int)); // disable nagle algorithm
}
}
return clientfd;
}
这行得通,但根据评论和回答,这不是可行的方法(显然,一种干净的方法与信号有关...)
只需在侦听(非阻塞)套接字上调用 accept()
。
如果积压中没有连接在等待,那么 accept()
会立即 return 并且 -1
并且 errno
将设置为 EGAIN
或 EWOULDBLOCK
.
来自 man accept
:
ERRORS
EAGAIN or EWOULDBLOCK
The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
然而,您显示的 while
-loop 将实现忙等待,这是相当昂贵的。
那么为什么不让 accept
通过简单地阻塞直到检测到传入连接来进行等待。
要中断阻塞 accept()
只需向进程发送一个信号。 accept()
然后将 return 与 -1
和 errno
设置为 EINTR
.
I would like to have a server that connects to one client
根据定义,始终是客户端连接到服务器。
我想要一台服务器一次连接到一个客户端,在连接到给定客户端时忽略连接请求。
我也想避免服务器在侦听第一个客户端时被锁定,这样程序就可以干净地终止。
显然,可以使套接字成为非阻塞的: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#blocking
我相应地创建了我的套接字(为清楚起见删除了错误管理代码)
int sockfd;
struct sockaddr_in self;
sockfd = socket(AF_INET, SOCK_STREAM, 0));
fcntl(sockfd, F_SETFL, O_NONBLOCK); // making this socket non blocking
bzero(&self, sizeof(self));
self.sin_family = AF_INET;
self.sin_port = htons(port);
self.sin_addr.s_addr = inet_addr("127.0.0.1"); // allowing connection from localhost only.
bind(sockfd, (struct sockaddr*)&self, sizeof(self));
从那时起,我不确定如何管理超时。以下代码不起作用,但给出了我想要实现的想法。
int client_found = 0;
while ( no_stop_signal && client_found==0 ) {
listen(sockfd,1);
if ( ** something that tells me nobody was requesting connection ** ) {
usleep(10);
} else {
client_found = 1;
}
}
到目前为止我找到的任何解决方案都关注比我的情况更复杂的情况(即一旦找到客户就不会忽略客户)并且看起来不必要地复杂。
编辑(接受答案后):
根据已接受的答案,这里是我附带的代码:
static inline int wait_for_client_to_connect(int sockfd, int* server_run){
int client_found = 0;
int clientfd = 0;
struct sockaddr_in client_addr;
int addrlen=sizeof(client_addr);
if ( listen(sockfd,1) != 0 ) return -1;
while ( client_found==0 && *server_run==1 ) {
clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);
if ( clientfd < 0 ) {
clientfd = 0;
if (errno==EAGAIN || errno==EWOULDBLOCK) usleep(10); // nobody connected, wait for request
else return -1; // something wrong, send error
} else { // client found, configuring socket and exit
client_found=1;
int nodelay_flag = 1;
setsockopt(clientfd, IPPROTO_TCP, TCP_NODELAY, (void*) &nodelay_flag, sizeof(int)); // disable nagle algorithm
}
}
return clientfd;
}
这行得通,但根据评论和回答,这不是可行的方法(显然,一种干净的方法与信号有关...)
只需在侦听(非阻塞)套接字上调用 accept()
。
如果积压中没有连接在等待,那么 accept()
会立即 return 并且 -1
并且 errno
将设置为 EGAIN
或 EWOULDBLOCK
.
来自 man accept
:
ERRORS
EAGAIN or EWOULDBLOCK
The socket is marked nonblocking and no connections are present to be accepted. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
然而,您显示的 while
-loop 将实现忙等待,这是相当昂贵的。
那么为什么不让 accept
通过简单地阻塞直到检测到传入连接来进行等待。
要中断阻塞 accept()
只需向进程发送一个信号。 accept()
然后将 return 与 -1
和 errno
设置为 EINTR
.
I would like to have a server that connects to one client
根据定义,始终是客户端连接到服务器。