Linux 使用 select() 系统调用监听 stdin 和服务器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5360660/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using select() system call for listening on stdin and the server
提问by Mir
I want to use select system call to multiplex STDIN and SOCKFD (connected to a server) such that I must be listening to both STDIN and SOCKFD and depending upon where the data is available for read I must proceed further.
我想使用 select 系统调用来多路复用 STDIN 和 SOCKFD(连接到服务器),这样我必须同时监听 STDIN 和 SOCKFD,并且根据数据可用于读取的位置,我必须继续进行。
Note: #define STDIN 0
注意:#define STDIN 0
This is what happens when I do the following.
当我执行以下操作时会发生这种情况。
- I connect to the server the usual way [ socket() then connect() ]
- I add STDIN and connection socket descriptor 'SOCKFD' to the fd_set (named 'readset') meant for reading.
- Then I call select().
- Use FD_ISSET to determine which fd is ready for read.
- 我以通常的方式连接到服务器 [ socket() 然后 connect() ]
- 我将 STDIN 和连接套接字描述符“SOCKFD”添加到用于读取的 fd_set(名为“readset”)中。
- 然后我调用 select()。
- 使用 FD_ISSET 来确定哪个 fd 准备好读取。
The problem with this set up is that FD_ISSET is always true for both the fd. Once I get connected to the server I see FD_ISSET(sockfd, &readset) is always true and so is FD_ISSET(STDIN, &readset) whether, the server is sending data or not or if I am entering data from keyboard or not.
这种设置的问题是 FD_ISSET 对 fd 始终为真。一旦我连接到服务器,我就会看到 FD_ISSET(sockfd, &readset) 始终为真,FD_ISSET(STDIN, &readset) 也是如此,无论服务器是否正在发送数据,或者我是否正在从键盘输入数据。
What could I be doing wrong?
我可能做错了什么?
/* connection successful */
/* 连接成功 */
FD_ZERO(&connset);
while(1) {
FD_SET(sockfd,&connset); /* add sockfd to connset */
FD_SET(STDIN,&connset); /* add STDIN to connset */
fdmax=sockfd;
if(select(fdmax+1,&readset,NULL,NULL,NULL)<0){
fprintf(stdout, "select() error\n");
exit(0);
}
/* select returned
* check which socket is set
*/
if(FD_ISSET(sockfd,&connset)) {
/*
* Server sends msglen
* client reads msg of length msglen
* client prints it to stdout
* client waits for next activity of its listen sockets
*/
size=4;
ptr=(char *)&msglen;
while(1) {
if((nread=recv(sockfd,ptr,size,0)),MSG_DONTWAIT) {
close(sockfd);
exit(0);
}
size-=nread;
ptr+=nread;
}
bytesToRead = ntohl(msglen);
readbuf = (char *)malloc(sizeof(char)*(bytesToRead+1));
ptr=readbuf;
while(1) {
nread=recv(sockfd,ptr,bytesToRead,MSG_DONTWAIT);
if(nread<=0) {
close(sockfd);
exit(0);
}
bytesToRead-=nread;
ptr+=nread;
}
/* msg read successfully */
*ptr='##代码##';
fprintf(stdout, "in: %s\n",readbuf);
free(readbuf);
}
if(FD_ISSET(STDIN,&connset)) {
/* data at STDIN */
fgets(buf,2,stdin); /* read the first newline char (< enter >) */
fprintf(stdout,"Enter msg: ");
fgets(buf,MAXLEN,stdin); /* read the msg */
buf[strlen(buf)-1]='##代码##';
msglen = htonl((uint32_t)(strlen(buf)-1));
ptr = (char *)&msglen;
bytesToSend = sizeof(uint32_t);
cnt = bytesToSend;
while(cnt>0) {
if((nsent=send(sockfd,ptr,cnt,0))>0) {
cnt-=nsent;
ptr+=nsent;
}
else {
fprintf(stdout,"send error\n");
exit(0);
}
}
ptr=buf;
bytesToSend=(uint32_t)(strlen(buf)-1);
cnt=bytesToSend;
while(cnt>0) {
if((nsent=send(sockfd,ptr,cnt,0))>0) {
cnt-=nsent;
ptr+=nsent;
}
else {
fprintf(stdout,"send error\n");
exit(0);
}
}
}
}
return 0;
}
}
采纳答案by AProgrammer
What is STDIN? There is stdin which is declared in <stdio.h>
, is a FILE* and not a file descriptor so can't be used in an fdset and STDIN_FILENO, which is defined in <unistd.h>
and is a file descriptor and thus can be used with fdsets.
什么是标准输入?在 中声明了 stdin,它是<stdio.h>
一个 FILE* 而不是文件描述符,因此不能在 fdset 和 STDIN_FILENO 中使用,它在 中定义<unistd.h>
并且是一个文件描述符,因此可以与 fdsets 一起使用。
BTW, in <stdio.h>
there is also a function fileno()
which returns the file descriptor of a FILE* (depending on your compilation flags, you may need to define some feature macros to get the declaration).
顺便说一句,<stdio.h>
还有一个函数fileno()
可以返回 FILE* 的文件描述符(根据您的编译标志,您可能需要定义一些功能宏来获取声明)。