我在学习使用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();
}
}
如果客户方发过的消息,服务器端一次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();
}
}
客户端:使用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个字节,在发送数据时,也使用固定大小缓冲区,这就是原因。
bytes = socket.Receive(RecvData, RecvData.Length, 0);
你查一下msdn就会发现Receive这个方法,当没有数据进来时,它会一直等待,除非设置了ReceiveTimeOut,否则会一直等下去,结果程序就假死在那里了一个可能的解决方法是:
if (socket.Available != 0)
{
bytes = socket.Receive(RecvData, RecvData.Length, 0);
}
else
{
bytes = 0;
}
这样可以在没有数据时跳出循环