我有两个独立的程序实例在不同的计算机上运行。它们通过TcpClient相互连接(井2连接,进入和传出,我知道TcpClient允许消息两种方式,但为了简化代码,更容易建立2个连接。)
两者都发送了大量消息,然后将在缓冲区中发送更多数据。两个线程都经历了一个阅读循环然后写作。
ReceiveIncomingMessagesFromTcpClient()
ParseAndDeliverIncomingMessagesInternaly()
CollectNewOutgoingMessagesInternaly()
DeliverOutgoingMessagesViaTcpClient()
我的程序似乎运行良好,然后停止发送消息,所以我担心这样做的原因是两者都试图将Outgoing消息写入各自的流,两个流都已满,并且没有任何内容可以清空我有一个陷入僵局的程序。
如果是这种情况,请在开始发送消息之前验证缓冲区中是否有空间,并且仅发送空间是什么? (为了避免阻塞发送,并由此导致死锁?)
我有这个发送数据的函数,它可以连续调用很多次。连接的缓冲区大小是默认的8kb。
因此,如果此操作连续多次重复,则8kb缓冲区将被填充,而stream.Write()是一个阻塞语句,直到另一方提取数据。
由于另一方是完美的镜像,如果它已经拉出大量数据要发送,双方可能会同时尝试发送,导致死锁。
private void DeliverOutgoingMessagesViaTcpClient()
{
for(int i = 0; i < message.Count;i++)
{
//send request
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message[i]);
NetworkStream stream = connection.GetStream();
stream.Write(data, 0, data.Length);
}
}
答案 0 :(得分:0)
根据反馈,似乎我的问题是当两个通信程序都阻止其发送消息时,我冒着阻止的风险。所以我现在将发送功能移到了一个单独的类中。
以下是我决定使用的课程。它应该在准备好使用后启动,并且可以使用目标TcpClient和消息调用,可以通过阻塞或非阻塞来执行调用(非阻塞返回true,接受消息)
public class TcpSender
{
Mutex moveToInternal = new Mutex();
Mutex startOnce = new Mutex();
List<Message> internalMessages = new List<Message>();
List<Message> externalMessages = new List<Message>();
Thread mainLoop;
String status = "stopped";
//returns true if started.
public Boolean Start()
{
if (startOnce.WaitOne(0))
{
status = "started";
mainLoop = new Thread(new ThreadStart(InternalMainLoop));
mainLoop.IsBackground = true;
mainLoop.Start();
return true;
}
return false;
}
private void InternalMainLoop()
{
while (status == "started")
{
Boolean didSomething = false;
//pickup new messages and move to internal buffer
if (externalMessages.Count > 0)
{
didSomething = true;
if (moveToInternal.WaitOne())
{
internalMessages.AddRange(externalMessages);
externalMessages.Clear();
moveToInternal.ReleaseMutex();
}
}
//deliver messages
for (int i = 0; i < internalMessages.Count; i++)
{
//send request
Byte[] data = System.Text.Encoding.ASCII.GetBytes(internalMessages[i].GetMessage());
NetworkStream stream = internalMessages[i].GetClient().GetStream();
stream.Write(data, 0, data.Length);
}
internalMessages.Clear();
if (!didSomething) Thread.Sleep(1); //Nothing to receive or send, maybe tomorr... next milisec there is something to do
}
startOnce.ReleaseMutex();
}
public void Stop()
{
status = "stopped";
}
public Boolean Status()
{
return (status == "started");
}
//return true if message was accepted
public Boolean addMessageNonBlocking(TcpClient client, String message)
{
Boolean gotMutex = false;
if(gotMutex = moveToInternal.WaitOne(0));
{
Message tmpMessage = new Message(client, message);
externalMessages.Add(tmpMessage);
moveToInternal.ReleaseMutex();
}
return gotMutex;
}
public void addMessageBlocking(TcpClient client, String message)
{
//loop until message is delivered
while (!addMessageNonBlocking(client, message))
{
Thread.Sleep(1); //could skip this, but no need for busy waiting
}
}
private class Message
{
TcpClient client;
String message;
public Message(TcpClient client, String message)
{
this.client = client;
this.message = message;
}
public TcpClient GetClient()
{
return client;
}
public String GetMessage()
{
return message;
}
}
}
用于验证TcpClient是否阻止的测试代码
将此代码添加到可以运行的任何位置。 testClient必须是连接到任何地方的TcpClient。
int i = 0;
String testmsg = "This is a 25 char test!!!";
Byte[] data = System.Text.Encoding.ASCII.GetBytes(testmsg);
while (true)
{
i++;
testClient.GetStream().Write(data, 0, data.Length);
if (i % 10 == 0) Console.WriteLine("Cycle Count: " + i);
}