日期:2014-05-16  浏览次数:21055 次

scanf 的阻塞问题
聊天室程序,如何解决scanf阻塞的问题?
客户端的select部分代码如下:
while( 1 )
  {
  /*记录集的初始化*/
  FD_ZERO( &sock_set );
  FD_SET( sockfd, &sock_set );
  FD_ZERO( &write_set ); //键盘标准输入流的监听
  FD_SET( 0, &write_set );

  /*时间初始化*/
tv.tv_sec = 5;
tv.tv_usec = 0;

  res = select( FD_SETSIZE, &sock_set, &write_set, NULL, &tv );
switch( res )
{
  case -1:
fprintf( stderr, "select error.\n" );
exit( EXIT_FAILURE );
  case 0:
break;
  default:
if( FD_ISSET(sockfd, &sock_set) || FD_ISSET(0, &write_set) )
{
if( FD_ISSET(sockfd, &sock_set) )
{
  nbytes = recv( sockfd, online_buff, sizeof(online_buff), 0 );
  if( nbytes < 0 )
{
fprintf( stderr, "接收数据错误..%s\n", strerror(errno) );
break;
}
else
{
if( nbytes != nbytes_temp )
{
nbytes_temp = nbytes;
  online_buff[nbytes] ='\0';
printf( "%s\n", online_buff );
}

}
}
 
 
if( FD_ISSET(0, &write_set) )
{
printf( "请输入您要选择聊天的的好友:" );
scanf( "%d", &n );
printf( "请输入您要发送给该好友的信息(不超过30个字符):" );
scanf( "%s", buffer );
cat_str_len( buffer, 30 );
sprintf( send_buffer, "%d:%s", n, buffer );

send( sockfd, send_buffer, strlen(send_buffer), 0 );
break;

}
 
}/*end big if*/
break;

  }/*end switch*/
  }/*end while 1*/

这个会产生阻塞问题...如果不scanf,就不能监听上面的记录集。。有没有上面方法避免scanf阻塞。
或者有没有什么方法给scanf设置一个输入时间,超过这个时间就会跳出去?
fork两个进程没有效果的,子进程会阻塞父进程。
求指导,万分感谢,给个思路就可以。

------解决方案--------------------
select只能判断标准输入0是否有数据,但这个数据不一定符合你的要求scanf( "%d", &n )等等
比如别人打了个空格,select也会认为0可读,但你scanf是无法获取到数据的,所以阻塞

解决方法(设置一个flag,为0 表示用户下一部是选择哪个好友;为1,表示用户已经选择好友,下一步是输入发送的数据:
select后,若flag = 0 ,则用read读取,然后检测读到的是不是表示一个数据,如果是,设置一下此时的flag = 1;表示用户已经选择了哪个好友。结束。如果不是,则表示用户输入错误,提示
若flag = 1,则用fgets或者read读取出来,再发送。

你在这里是不该用scanf的,因为0是行缓冲 , scanf是格式化读取。
对于"%s", 空格读不出,且是分隔符,,,使用fgets读取一行的输入

------解决方案--------------------
接收与发送单独做线程,互不影响。
------解决方案--------------------
5楼最彻底,
------解决方案--------------------
五楼正解 这种事本来就是异步的好

还有如果非得用上面的方面 可以用定时器这个东西 在调用sacnf之前触发定时 时间到了发送定时间超时信号 然后再信号处理函数里面就可以跳过scanf了 我是这么想的 应该有效