我正在使用一个服务器和一个客户端进行项目以进行模拟。目标是开发一个可以使用TCP和UDP同时与100个客户端通信的服务器。我正在为服务器和客户端使用TCPListener和UDPClient。我正在使用多线程,创建一个对象类。
我的代码有两个问题:
在运行期间,UDP数据包丢失,冻结了一些线程。
UDP的发送/接收速度非常不同(线程2发送2000与线程4发送900等)
此外,当我运行10个Threads时,它将完美地运行。但是当线程数量增加时,就会出现这些问题。
我有以下代码↓
客户端(接收功能):
rpacket = new byte[1024];
//#0: UDP packet timeout
// is this necessary?? I could use while loop to measure waiting time.
net.tClient.Client.ReceiveTimeout = 1000;
net.client.Client.ReceiveTimeout = 1000;
//net.client.Client.SendTimeout = 2000;
// #1: message
_logIt(false, localThreadId, "started receivedata for threadid" + localThreadId);
// #2: number of received data recording
int nReceived = 0;
// #3: loop runs forever...
while (true)
{
// receiving data
bool recursion = false;
int recursionCount = 0;
int bytesReceived = 0;
// receiving data
bytesReceived = messageReceive(out recursion);
while (recursion == true)
{
// check if there are data 3 times
bytesReceived = messageReceive(out recursion);
recursionCount++;
if (recursionCount <= 3)
{
if (recursionCount == 1 && rIndex > 0)
{ rIndex--; }
// resend message
if (net.q[rIndex][1] == 0x00)
{
// sending data to PICS
// changed net.q[rIndex].Length - 1 to changed net.q[rIndex].Length - 2
try
{
int nBytesSend = net.client.Send(tempData, tempData.Length, net.ipEndPoint);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
// if 0x01, the protocl is TCP
else if (net.q[rIndex][1] == 0x01)
{
try {
int nBytesSend = net.tClient.Client.Send(tempData, tempData.Length, SocketFlags.None);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
else if (recursionCount == 4)
{
// hoot~ byebye
recursion = false;
Usage("hoot");
}
}
}
客户端(发送功能):
// if 0x00, the protocol is UDP
if (net.q[rIndex][1] == 0x00)
{
// sending data to PICS
// changed net.q[rIndex].Length - 1 to changed net.q[rIndex].Length - 2
int nBytesSend = net.client.Send(data, net.q[rIndex].Length - 2, net.ipEndPoint);
}
// if 0x01, the protocl is TCP
else if (net.q[rIndex][1] == 0x01)
{
int nBytesSend = net.tClient.Client.Send(data, net.q[rIndex].Length - 2, SocketFlags.None);
}
// June 1th, tempData is only used for failed messages
if (data.Length != 0)
{ tempData = data; }
Array.Resize(ref tempData, data.Length);
net.nSent++;
totalSent[localThreadId]++;
if (verbosity)
_logIt(false, localThreadId, "# of data sent: " + net.nSent);
// after sending, set the queue[][0] to 0x00
net.q[rIndex][0] = 0x00;
// setting queue[][1] is not neccessary...
rIndex++;
消息接收(输出递归):
messageReceive(out bool audi)
{
int numBytes = 0;
audi = false;
// updated try and catch method, because there can be udp or tcp
try
{
rpacket = net.client.Receive(ref net.ipEndPoint);
numBytes = rpacket.Length;
}
catch (SocketException ex)
{
try
{
numBytes = net.tClient.Client.Receive(rpacket);
Array.Resize(ref rpacket, numBytes);
}
catch (Exception exc)
{
audi = true;
Console.WriteLine(exc.Message);
}
}
return numBytes;
}
服务器端与客户端相同。
仅供参考:有一个名为queue的二维字节数组,用于存储将发送给远程用户的所有数据。 wIndex是一个整数,用于将回复数据写入队列。 rIndex是一个整数,用于从队列中读取回复数据并将其发送给远程用户。
如何解决我的问题?
答案 0 :(得分:0)
警告使用多个线程通过套接字发送/接收会锁定程序中的套接字及其I / O操作。
当您使用套接字时,最好使用套接字提供的异步,例如BeginRead
和'EndRead',因为它们使程序将在同一个线程上运行并避免套接字 - 客户端被封锁另外,不要在socket-clients中使用sleep,它们会阻塞socket。
检查此答案:C# High CPU usage on Listener thread, sleeping misses disconnect
在这个答案中,我展示了如何使用BeginRead
和WriteRead
。