我在学习使用socket编程,写了一个服务程序用来侦听客户端传过来的请求信息。 
如果客户方发过的消息,服务器端一次receive完,程序没有问题。 
如果,服务器分多次receieve的话,客户端程序就会没有反应, 
服务器端接受的消息也不会反应到richtextbox中(一次receieve是马上会显示的), 
一直要等到客户端程序关闭。服务器端,才会把接受的消息显示在richtextbox中。 
想不通。希望大家帮忙解惑。谢谢!   如果要看完整的代码,请参考下面两个连接: 
服务器程序连接:http://community.csdn.net/Expert/topic/3192/3192347.xml?temp=.8513452 
客户端程序连接:http://community.csdn.net/Expert/topic/3192/3192353.xml?temp=.8600733 
服务器端:(我删节了一部份不太关键的代码希望大家能够看懂) //在窗体load的时候启动一个侦听线程。 
private   void   QuoteSvrForm_Load(object   sender,   System.EventArgs   e) 

//创建一个网络侦听线程。 
listenerThread   =   new   Thread(new   ThreadStart(this.Listener)); 
//启动网络侦听线程。 
listenerThread.Start(); 

//线程实体部分。 
private   void   Listener() 

byte[]   RecvData   =   new   byte[10];//接受缓存设为10个字节。 
Int32   bytes; 
string   RequestMessage   =   " "; 
Encoding   myEncoding   =   Encoding.ASCII; 
IPAddress   myIP   =   IPAddress.Parse( "127.0.0.1 "); 
int   port   =   4567; 
listener   =   new   TcpListener(myIP,port); 
listener.Start(); 
while   (true) 

if   (listener.Pending())//确定是否有挂起的连接请求。 

Socket   socket   =   listener.AcceptSocket(); 
if   (socket   ==   null) 
return; 
//接收客户端的请求信息; 
bytes   =   socket.Receive(RecvData,     RecvData.Length,   0); 
RequestMessage   =   myEncoding.GetString(RecvData,   0,   bytes); 
//如果没有这个while语句,就没有问题了。各位可以试一下。 
while   (   bytes   >   0   ) 

bytes   =   socket.Receive(RecvData,     RecvData.Length,   0); 
RequestMessage   =   RequestMessage   +     myEncoding.GetString(RecvData,   0,   bytes); 
} if   (RequestMessage.Length   >   0) 

this.richTextBox_Request.Text   =   RequestMessage; 

socket.Close(); 


} 客户端程序: 
private   void   buttonQuote_Click(object   sender,   System.EventArgs   e) 

this.statusBar1.Text   =   " "; 
//服务器的IP地址; 
string   server   =   this.textHost.Text; 
int   port   =   4567; 
//服务器的端口; 
try 

port   =   Convert.ToInt32(this.textPort.Text); 

catch(FormatException   ex) 

this.statusBar1.Text   =   ex.Message; 
return; 

//   要发送到服务器的消息; 
string   message   =   this.richTextBox1.Text; 
//   TcpClient; 
TcpClient   client   =   new   TcpClient(); 
try 

//   连接到服务器; 
client.Connect(server,port); 
//   获得用于网络访问的基础数据流; 
NetworkStream   stream   =   client.GetStream(); 
//   将消息转换为字节数组; 
Byte[]   requestData   =   System.Text.Encoding.ASCII.GetBytes(message); 
//   发送消息的字节数组; 
//stream.Write(requestData,0,requestData.Length); 
stream.BeginWrite(requestData,0 

catch(SocketException   ex) 

this.statusBar1.Text   =   ex.Message; 

finally 

//MessageBox.Show( "client   close "); 
client.Close(); 

}

解决方案 »

  1.   

    我来分析一下你的程序: 
    客户端:使用NetworkStream的Write方法写入一些数据,完成后执行finally块中的Close方法关闭网络连接。 
    服务器端:一次读取10   Byte数据,转换后加到字符串中。如果数据接收完,则把字符串赋予RichText。 
    你的问题是:服务器端总是没反应,要等待客户端关闭连接后,才有反应。 问题的原因是: 
    假设你的客户端发送的内容很长,假设10K吧,服务器端要接收1024次,然后执行1024次GetString,执行1024次String类的加方法,注意,这些都是很费时间的,尤其是你一次只接收10字节,那要循环很多次才能读完所有数据,那要花多少时间啊。 
    这些完成后,再赋予RichText。在执行过程中是不会看到RichText中的数据的,因为你的程序就是写成要服务器端再也接收不到数据(readByte   不大于0)时,才更新RichText嘛。 
    至于客户端没反应嘛,是因为你使用的Write方法,要等待发送完所有数据才会返回。因为你服务器处理数据的速度慢,这样它的接收缓冲区很快就满了,客户端也就不能发送数据了,要等待服务器处理掉一部分数据,接收缓冲区有空间之后,客户端才能继续发送数据。所以客户端就被服务器速度拖累也似乎没反应了。 
    解决办法是:增大服务器读取网络的缓冲区,一般至少1024字节,还可以增大,当然,你也可以使用4096字节,这是.NET在很多IO操作中默认的缓冲区大小。这样可以大大减少你等待的时间。你还可以使用StringBuilder类而不是String类,来进一步减少总时间。 另外,你的服务器还存在问题:无法同时为多个客户服务。因为你是在接受一个Socket之后直接为它服务,服务完成后再接受其他客户,这只适用于处理量小的情况下(如Time服务)。但估计你的服务器也只想为一个用户服务的。 你的客户端也存在问题:不应把所有数据一次通过Write方法发送。一般作法是分次发送,一次1024字节或者4K或者其它大小。这样也能够提高发送效率,特别是在你要发送大量数据的时候。 所以在示例代码中,你总会看到一般把接收缓冲区设置为1024或者其它数字的,绝看不到象你一样的10个字节,在发送数据时,也使用固定大小缓冲区,这就是原因。
      

  2.   

    关键是因为这句:
    bytes = socket.Receive(RecvData, RecvData.Length, 0);  
    你查一下msdn就会发现Receive这个方法,当没有数据进来时,它会一直等待,除非设置了ReceiveTimeOut,否则会一直等下去,结果程序就假死在那里了一个可能的解决方法是:
    if (socket.Available != 0)
    {
       bytes = socket.Receive(RecvData, RecvData.Length, 0);  
    }
    else
    {
       bytes = 0;
    }
    这样可以在没有数据时跳出循环
      

  3.   

    socket编程里的通信方式有TCP和UDP 不知道你用的是哪种,是否用了多线程对息的同步和异步进行了处理,我怀疑问题就是处在 异步处理这个地方!