【问题标题】:getline() function behaves strangelygetline() 函数行为异常
【发布时间】:2011-10-18 21:08:05
【问题描述】:

我正在尝试通过编写套接字侦听器程序来模拟 telnet 功能,并且应用程序通过套接字将其控制台重定向到侦听器。

在服务器端,我在本地 ip 上打开了一个套接字,一个定义的端口,并开始像这样监听它

sockfd = socket(AF_INET,SOCK_STREAM,0);
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr);
listen(sockfd,5);
neewsockfd = accept(sockfd,(struct sockaddr*)&cli_addr,&clien);

然后我开始在一个单独的线程中读取传入的数据,如下所示:

while(1)
{
  bzero(buffer,256);
  n= read(newsockfd,buffer,255);
  if(n>0)
     printf("%s",buffer);
}  

在监听代码之后的主程序中,我添加了这样的套接字数据发送部分。

while(1)
{
   bzero(buffer,256);
   getline(&buffer,&t,stdin);
   n=send(newsockfd,buffer,strlen(buffer),MSG_EOR);
}

对于客户端部分,我已经像这样连接到服务器。

sockfd = socket(AF_INET,SOCK_STREAM,0);
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
inet_pton(AfF_INET,hostip,&serv_addr.sin_addr.s_addr)
serv_addr.sin_port = htons(portno);
connect(sockfd,serv_addr,sizeof(serv_addr));

然后我将 stdin、stdout 和 stderr 复制到 sockfd 描述符以重定向控制台,如下所示。

 dup2(sockfd,STDIN_FILENO);
 dup2(sockfd,STDOUT_FILENO);
 dup2(sockfd,STDERR_FILENO);

 close(sockfd);

最后我在客户端有这样的东西来测试控制台重定向

while(1)
{
   bzero(mystring,256);
   i = getline(&string,&t,stdin);
   printf("Input:%s-%d\n",mystring,i);
}

在上面的代码中,我希望 getline 会被阻止,直到我在服务器应用程序控制台上输入一些字符,但对于我的痛苦,它会重复出现值 0。

知道为什么会出现这种行为吗?

【问题讨论】:

  • getline(&string,&t,stdin) 你的问题是错字吗?您初始化 mystring,您尝试打印 mystring 但您在字符串中“getline” ...
  • 是的,这是一个错字,应该是 mystring
  • 是的,正确的代码是这样 while(1) { bzero(mystring,256); i = getline(&mystring,&t,stdin); printf("输入:%s-%d\n",mystring,i); }
  • 我假设您正在检查所有这些调用(连接、发送等)以查看它们是否返回 -1?我将首先在每个进程上使用lsof,以确保文件描述符实际上是打开的套接字连接,就像您期望的那样。
  • 这只是用于理解问题的代码 sn-p,在我的实际程序中,我会检查所有错误返回。

标签: c linux sockets


【解决方案1】:

将套接字与stdio(3) 混合使用是个坏主意TMstdinstdout 都是 line-buffered,请参阅 setbuf(3),这可能就是让您来到这里的原因。还有一个线程安全问题 - stdio 流被锁定,但由于您已经使用 GNU 扩展,您可以尝试他们的 unlocked 对应项。

编辑0:

根据您在 cmets 中的输入,我认为这将是解决方案:

  • 在做fork(2)之前在父进程中创建一个pipe(2)
  • fork(2)之后但execve(2)之前的chaild进程dup2(2)管道的读取文件描述符到STDIN
  • 在新的exec-ed 子进程中只读取标准输入
  • 在父进程中复制标准输入到管道的写文件描述符中。

这应该可以避免大部分混淆。

【讨论】:

  • 如果通过 fdopen() 从它们创建一个新的FILE 对象,但替换已打开文件和缓冲文件的文件描述符(如 stdin 和 @ 987654340@) 无法可靠地工作。
  • 我的要求是与运行时启动的进程进行控制台交互。由于新启动的进程的stdio也指向当前进程的stdio,因此很难与两个进程进行交互。很多人建议用这种描述符代替这个问题的方法。
  • 不完全确定您在这里的意思,但您似乎想探索 I/O 多路复用的 select(2)poll(2) 系列函数。
  • 我想要的是,我的 scanf 和其他 stdin 函数接受来自这两个进程的输入。由于两个进程(一个从另一个进程启动的进程)都将指向同一个控制台,因此不可能通过同一个控制台向不同的应用程序提供输入,不是吗?如果 select(2) 和 poll(2) 可以用来解决我的问题,你能详细说明一下吗?
  • 您能否用一些流程层次结构的描述以及您希望它们如何交互来更新问题?我对你在做什么感到困惑。
猜你喜欢
  • 1970-01-01
  • 2022-12-04
  • 1970-01-01
  • 2019-03-25
  • 1970-01-01
  • 1970-01-01
  • 2014-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多