[英]BSD Sockets - How to use non-blocking sockets?
我正在嘗試使用非阻塞 TCP sockets。 問題是他們仍然在阻塞。 代碼如下 -
服務器代碼 -
struct sockaddr name;
char buf[80];
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
int main(int agrc, char** argv) {
int sock, new_sd, adrlen; //sock is this socket, new_sd is connection socket
name.sa_family = AF_UNIX;
strcpy(name.sa_data, "127.0.0.1");
adrlen = strlen(name.sa_data) + sizeof(name.sa_family);
//make socket
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
printf("\nBind error %m", errno);
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, &name, adrlen) < 0)
printf("\nBind error %m", errno);
//listen
if(listen(sock, 5) < 0)
printf("\nListen error %m", errno);
//accept
new_sd = accept(sock, &name, (socklen_t*)&adrlen);
if( new_sd < 0) {
cout<<"\nserver accept failure "<<errno;
exit(1);
}
//set nonblock
set_nonblock(new_sd);
char* in = new char[80];
std::string out = "Got it";
int numSent;
int numRead;
while( !(in[0] == 'q' && in[1] == 'u' && in[2] == 'i' && in[3] == 't') ) {
//clear in buffer
for(int i=0;i<80;i++)
in[i] = ' ';
cin>>out;
cin.get();
//if we typed something, send it
if(strlen(out.c_str()) > 0) {
numSent = send(new_sd, out.c_str(), strlen(out.c_str()), 0);
cout<<"\n"<<numSent<<" bytes sent";
}
numRead = recv(new_sd, in, 80, 0);
if(numRead > 0)
cout<<"\nData read from client - "<<in;
} //end while
cout<<"\nExiting normally\n";
return 0;
}
客戶端代碼 -
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
int main(int agrc, char** argv) {
int sock, new_sd, adrlen;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//stuff for server socket
name.sa_family = AF_UNIX;
strcpy(name.sa_data, "127.0.0.1");
adrlen = strlen(name.sa_data) + sizeof(name.sa_family);
if(connect(sock, &name, adrlen) < 0) {
printf("\nclient connection failure %m", errno);
exit(1);
}
cout<<"\nSuccessful connection\n";
//set nonblock
set_nonblock(sock);
std::string out;
char* in = new char[80];
int numRead;
int numSent;
while(out.compare("quit")) {
//clear in
for(int i=0;i<80;i++)
in[i] = '\0';
numRead = recv(sock, in, 80, 0);
if(numRead > 0)
cout<<"\nData read from server - "<<in;
cout<<"\n";
out.clear();
cin>>out;
cin.get();
//if we typed something, send it
if(strlen(out.c_str())) {
numSent = send(sock, out.c_str(), strlen(out.c_str()), 0);
cout<<"\n"<<numSent<<" bytes sent";
}
} //end while
cout<<"\nExiting normally\n";
return 0;
}
每當我運行它時,服務器仍然等待我發送一些東西,然后它才會讀取客戶端發送的內容和 output。 我希望服務器或客戶端能夠在我鍵入消息后立即發送消息,並讓另一個讀取並在當時 output 消息。 我認為非阻塞 sockets 是答案,但也許我只是做錯了什么?
另外,我使用文件而不是我的 127.0.0.1 地址作為 sockaddr 的數據。 如果這不是正確使用它的方式,請隨意這么說(它以前使用文件的方式工作,所以我就這樣保留它)。
任何幫助表示贊賞。
您希望同時處理多個連接的 TCP 服務器的一般方法:
select(2)
或poll(2)
讀取事件集select(2)
/ poll(2)
循環accept(2)
EAGAIN
錯誤代碼 - 這不是真正的錯誤,但表明現在沒有輸入close(2)
客戶端套接字,將其從事件集中刪除select(2)
的常見錯誤)客戶端稍微簡單一些,因為您只有一個套接字。 處理許多連接的高級應用程序(例如 web 瀏覽器)通常會執行非阻塞connect(2)
。
我認為您必須盡快設置非阻塞(即獲取套接字然后將其設置為非阻塞)
還要檢查設置它的 fcntl 是否實際工作
每當我運行它時,服務器仍然等待我發送一些東西,然后它才會讀取客戶端發送的內容和 output。
嗯,你就是這么寫的。 您從標准輸入阻止 IO,然后才進行發送/接收。
cin>>out;
cin.get();
此外,您正在使用本地套接字(AF_UNIX),它在您的文件系統中創建一個特殊文件以進行進程間通信 - 這是與 IP 不同的機制,並且絕對不是您在問題中指出的 TCP。 我想您可以將文件命名為127.0.0.1 ,但這確實沒有意義,並且意味着您會感到困惑,因為那是 IP 環回地址。 您需要將 AF_INET 用於 IP。
對於 unix 網絡的優秀入門指南,我推薦http://beej.us/guide/bgnet/
如果您希望接收到的消息的顯示與您的 cin 語句無關,請 fork() 關閉一個單獨的進程來處理您的網絡 IO,或者使用單獨的線程。
您可能對 select() 感興趣。 在我看來,非阻塞 sockets 通常是一個 hack,正確使用 select() 或 poll() 通常是更好的設計和更靈活(並且更便攜)。 嘗試
人 select_tut
了解更多信息。
如果你想要非阻塞 i/o,你想使用 select。 您可以使用 stdin 將其設置為它正在偵聽的 sockets (只需將文件描述符 1,即 stdin,添加到 fd_set)之一。
http://beej.us/guide/bgnet/output/html/multipage/advanced.html
我建議閱讀 beej 對 select 的評價。 它看起來有點嚇人,但如果您花一點時間來了解它,它確實非常有用且易於使用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.