在复制套接字描述符后,Scanf(实际上我尝试过任意数量的scanf' s)跳过。以下是您可以编译以查看问题的代码:
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
int dupfd = 0;
dup2(listenfd, dupfd);
puts("Type something to exit");
int exit = -1;
scanf("%d", &exit);
puts("Got exit signal");
return 0;
}
答案 0 :(得分:2)
我猜错误是,你应该dup2()连接套接字,而不是监听套接字。以下示例适用于我(在端口32000中连接telnet进行测试):
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <strings.h>
int main()
{
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
int dupfd = 0;
int connfd,n;
struct sockaddr_in servaddr,cliaddr;
socklen_t clilen;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
listen(listenfd,1024);
connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
dup2(connfd, dupfd);
puts("Type something to exit");
int exit = -1;
scanf("%d", &exit);
printf("%d\n", exit);
puts("Got exit signal");
return 0;
}
请记住,在套接字上使用scanf()是一个坏主意,因为scanf()只阻塞一次;也就是说,一旦它收到消息的任何部分,即使是单个字符,它也会解析它收到的字符串。如果不完整,解析将是不正确的。
网络套接字可以以任意数量的较小块传递消息。通常它会以数据包形式发送它,但它甚至可以逐个字符地发送。此示例“倾向于与Telnet一起工作”,因为客户端仅在按Enter时发送键入的字符串。但对于实际的网络服务器来说,这是完全不够的。
答案 1 :(得分:2)
如果您仅使用read
代替scanf
并控制错误,则会更清楚:
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
int main()
{
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
int dupfd = 0;
dup2(listenfd, dupfd);
puts("Type something to exit");
int exit = -1;
//scanf("%d", &exit);
char buf[16];
int n = read(0, buf, 16);
printf("Got %d (%d)\n", n, errno);
puts("Got exit signal");
return 0;
}
程序输出Got -1 (57)
,因为在dup2
之后,您正试图从侦听套接字读取。因此,您会收到原因为ENOTCONN
的读取错误:Socket未连接
所有这些都是因为dup2
而发生的。以下是手册页中的一些摘录: dup()系统调用复制现有对象描述符...在dup2()中,指定新描述符newd的值。如果此描述符已被使用且oldd!= newd,则首先释放描述符,就好像已使用close(2)系统调用一样。
0,1和2是标准文件描述符:1 =输入,2 =输出,3 =错误。因此,int dupfd = 0; dup2(listenfd, dupfd);
会关闭标准输入并将其作为listenfd
的副本。之后,所有scanf
或read(0, ...)
都会对listendfd
采取行动。恕我直言,你想做的只是:
int dupfd = dup(listenfd);
这样你实际上得到listenfd
的副本,但是在未使用的文件描述符上而不是重用标准输入。