[英]Enable non-blocking socket
我有一台用C / C ++編寫的服務器。 我將連接器的包裝設置如下:
//START WRAPPER
void Server::init_address(int port)
{
memset(&(this->serv_addr), 0, sizeof(this->serv_addr));
this->serv_addr.sin_family = AF_INET;
this->serv_addr.sin_port = htons(port);
this->serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
}
int Server::w_socket()
{
int retv;
retv = socket(PF_INET, SOCK_STREAM, 0);
//FIXME
//fcntl(retv, F_SETFL, O_NONBLOCK);
if(retv == -1)
{
std::string err_msg(strerror(errno));
err_msg = "[socket] " + err_msg;
throw err_msg;
}
else
{
int reuse_opt = 1;
if(setsockopt(retv, SOL_SOCKET, SO_REUSEADDR, &reuse_opt, sizeof(int))==-1)
{
perror("setsockopt error");
exit(1);
}
return retv;
}
}
void Server::w_bind()
{
int retv;
retv = bind(this->sock_fd,
(struct sockaddr*) &(this->serv_addr),
sizeof(this->serv_addr));
if(retv == -1)
{
std::string err_msg(strerror(errno));
err_msg = "[bind] " + err_msg;
throw err_msg;
}
}
void Server::w_listen()
{
int retv;
retv = listen(this->sock_fd, 3);
if (retv == -1)
{
std::string err_msg(strerror(errno));
err_msg = "[listen] " + err_msg;
throw err_msg;
}
}
int Server::w_accept(struct sockaddr_in* client_addr)
{
int retv;
int socklen = sizeof(sockaddr_in);
retv = accept(this->sock_fd, (struct sockaddr*)client_addr, (socklen_t*)&socklen);
if(retv == -1)
{
std::string err_msg(strerror(errno));
err_msg = "[accept] " + err_msg;
throw err_msg;
}
else
{
return retv;
}
}
int Server::recvtimeout(int s, char *buf, int len, int timeout)
{
fd_set fds;
int n;
struct timeval tv;
// set up the file descriptor set
FD_ZERO(&fds);
FD_SET(s, &fds);
// set up the struct timeval for the timeout
tv.tv_sec = timeout;
tv.tv_usec = 0;
// wait until timeout or data received
n = select(s+1, &fds, NULL, NULL, &tv);
if (n == 0){
return -2; // timeout!
}
if (n == -1){
return -1; // error
}
// data must be here, so do a normal recv()
return recv(s, buf, len, 0);
}
// END WRAPPER
我的目標是啟用非阻塞套接字模式。 我試圖做fcntl(retv,F_SETFL,O_NONBLOCK); 就像Beej手冊說的那樣,但是我收到錯誤消息: [accept]資源暫時不可用解決此問題的方法是使用select函數,但我已經像recjetimeout函數那樣使用了它,就像Beej guide所說的那樣。
因此,我不知道如何解決此問題以啟用非阻塞套接字模式。
由於套接字未阻塞,您會收到錯誤消息。
在收到該錯誤時,您要么做一個忙循環(當accept
為EWOULDBLOCK
或EAGAIN
返回-1
時檢查errno
)。 另一個推薦的解決方案是使用select
查看套接字何時可讀,然后可以調用accept
。
編輯:如何select
您需要在更高級別上有一個事件循環,該循環檢查是否可以讀取偵聽套接字或連接的套接字。 如果偵聽套接字是可讀的,那么您可以接受新的連接;如果連接的套接字是可讀的,則可以從中讀取。
就像是:
for (;;)
{
fd_set readset;
FD_ZERO(&readset);
FD_SET(listening_socket, &readset);
int maxfd = listening_socket;
if (connected_socket >= 0)
{
FD_SET(connected_socket, &readset);
maxfd = max(maxfd, connected_socket);
}
// NULL timeout (5-th argument) means wait until event
select(maxfd + 1, &readset, NULL, NULL, NULL);
if (FD_ISSET(listening_socket, &readset))
{
accept_new_connection(listening_socket);
}
if (connected_socket >= 0 && FD_ISSET(connected_socket, &readset))
{
if (!read_from_socket(connected_socket))
{
close(connected_socket);
connected_socket = -1;
}
}
}
如果您有多個已連接的套接字,請將它們放入一個簡單的鏈表中,並循環添加/檢查它們。 當它們關閉時,從列表中刪除。
在您的解決方案中,您將select
調用用於連接套接字,但未將其用於listen socket
。
如果您還將listen socket
也更改為非阻塞listen socket
,那么在調用accept
之前必須對listen socket
使用select。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.