我正在尝试使用非阻塞TCP套接字。问题是它们仍在阻塞。代码如下 -
服务器代码 -
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;
}
每当我运行它时,服务器仍会等待我发送内容,然后才会读取并输出客户端发送的内容。我希望服务器或客户端能够在我键入消息后立即发送消息,然后让另一个读取并输出消息。我认为非阻塞套接字是答案,但也许我只是做错了什么?
另外,我使用的是一个文件而不是我的127.0.0.1地址作为sockaddr的数据。如果这不是应该如何正确使用,请随意这样说(它的工作原理如何以前使用文件,所以我只是保持这样)。
感谢任何帮助。
答案 0 :(得分:4)
要在同一时间处理多个连接的TCP服务器的一般方法:
select(2)
或poll(2)
阅读事件集select(2)
/ poll(2)
循环accept(2)
EAGAIN
错误代码 - 这不是一个错误,但表示现在没有输入 close(2)
客户端套接字,则将其从事件集select(2)
)客户端更简单,因为您只有一个套接字。处理许多连接的Web浏览器等高级应用程序通常会进行非阻塞connect(2)
。
答案 1 :(得分:3)
我认为你必须尽快设置非阻塞(即获取套接字然后将其设置为非阻塞)
还检查fcntl设置它实际上是否有效
答案 2 :(得分:3)
每当我运行它时,服务器仍会等待我发送内容,然后才会读取并输出客户端发送的内容。
嗯,这就是你写它的方式。你从stdin上阻止了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()感兴趣。在我看来,非阻塞套接字通常是一个hack,正确使用select()或poll()通常更好的设计和更灵活(和更便携)。试试
man select_tut
了解更多信息。
答案 3 :(得分:0)
如果您想要非阻塞i / o,则需要使用select。您可以将stdin设置为它正在侦听的套接字之一,以及客户端套接字(只需将文件描述符1(stdin)添加到fd_set)。
http://beej.us/guide/bgnet/output/html/multipage/advanced.html
我建议阅读beej关于选择的内容。它看起来有点令人生畏,但是如果你花点时间把它包裹起来,它真的很有用而且很简单。