C# C“套接字TCP发送,消息获取”;";
这有点奇怪,如果我解释得不好,我道歉 我使用下面的简单代码发送我从队列中弹出的消息,使用一个简单的TCP套接字,消息通过本地主机发送到同一台机器上的另一个端口-C# C“套接字TCP发送,消息获取”;";,c#,sockets,tcp,C#,Sockets,Tcp,这有点奇怪,如果我解释得不好,我道歉 我使用下面的简单代码发送我从队列中弹出的消息,使用一个简单的TCP套接字,消息通过本地主机发送到同一台机器上的另一个端口- try { Socket.Select(null, writeList, null, 120000000/*120 seconds*/); } catch (SocketException e) { log.Error("Select returned an error waiting to send... " + e.
try
{
Socket.Select(null, writeList, null, 120000000/*120 seconds*/);
}
catch (SocketException e)
{
log.Error("Select returned an error waiting to send... " + e.Message + " Errorcode: " + e.ErrorCode);
connected = false;
socket.Close();
}
bool readyToWrite = false;
for (int i = 0; i < writeList.Count; i++)
{
readyToWrite = true;
}
if (readyToWrite)
{
try
{
//log.Debug("Sending message type: " + message.header.msgType);
socket.Send(message, message.header.dataLength, SocketFlags.None);
//log.Debug("Message sent");
}
catch (SocketException e)
{
log.Error(e.Message + " Error code: " + e.ErrorCode);
connected = false;
socket.Close();
}
}
else
{
log.Error("Not able to write - stopping sender thread and closing socket");
connected = false;
socket.Close();
}
以及读取方法-
int CReadWriteSocket::Read(void *pData, int nLen)
{
char* pcData = (char* )pData;
int n = nLen;
// if data size is bigger then network buffer
// handle it nice
do
{
int r1 = ::recv (m_hSocket, pcData, n, 0);
if (r1 == SOCKET_ERROR)
{
int e = WSAGetLastError();
if (e == WSAEWOULDBLOCK)
{
return nLen - n;
}
else
{
TRACE("Socket Read error %d\n", e);
return -1; // error other than would block detected
}
}
else if (r1 == 0) // Connection has closed
{
TRACE("Socket appears to have closed (zero bytes read)\n");
return -1; // Show this as an "error"
}
else if (r1 < 0)
{
ASSERT(0);
return nLen - n;
}
pcData += r1;
n -= r1;
} while (n > 0);
ASSERT(n == 0);
return nLen;
}
int-CReadWriteSocket::Read(void*pData,int-nLen)
{
char*pcData=(char*)pData;
int n=nLen;
//如果数据大小大于网络缓冲区
//好好处理
做
{
int r1=:recv(m_hSocket,pcData,n,0);
if(r1==套接字错误)
{
int e=WSAGetLastError();
如果(e==WSAEWOULDBLOCK)
{
返回nLen-n;
}
其他的
{
跟踪(“套接字读取错误%d\n”,e);
return-1;//检测到块以外的错误
}
}
如果(r1==0)//连接已关闭,则为else
{
跟踪(“套接字似乎已关闭(读取零字节)\n”);
return-1;//将其显示为“错误”
}
否则如果(r1<0)
{
断言(0);
返回nLen-n;
}
pcData+=r1;
n-=r1;
}而(n>0);
断言(n==0);
返回nLen;
}
我完全糊涂了,因为这似乎是我到处使用的标准代码,我从来没有见过这样的问题发生
有人建议尝试使用NoDelay套接字选项,但没有任何效果——事实上,根据我所知,这永远不会导致如此长的延迟
如有任何建议,将不胜感激!谢谢。TCP是一种流协议。您不能假设您发送()的“数据包”将被传递和接收。在传输端,Nagle算法尝试组合在单独的Send()调用中写入的数据,以优化数据的传递。在接收端,您将读取()存储在TCP缓冲区中的内容。如果有任何延迟,If将是传输数据包的组合。发射机和接收机之间的路由器使这一点更加复杂,允许它们将一个IP数据包分割成多个小数据包,以适应传输信道的最大数据包大小(MTU)
换句话说,没有可靠的方法来确保数据包按发送方式发送。一个简单的解决方法是首先传输数据包的大小。在接收端,您首先读取该大小,然后知道如何计算接收到的字节数以重建数据包。这很奇怪。请考虑使用这些信息来追踪消息,看看它们将走向何方。除非我遗漏了一些明显的信息,否则我很难理解为什么这些信息认为它们已经收到,但实际上没有收到。客户会等吗
尝试int.MaxValue而不是120000000我不确定这是否是您的问题,我正在利用去年的模糊记忆,因此请原谅这种模糊 我似乎记得,
Socket.Select()
会返回,指示如果流有错误,它没有要读取的数据。您可能希望尝试将流列表的副本传递给error list参数,并查看是否有任何错误
无论writelist
中有什么内容,您的代码似乎正在发送到同一个套接字。即使您只有一个套接字,我也会将其修改为在writelist
上操作。否则,您将尝试发送到套接字,即使它不一定表示它已准备好接收数据(即,socket.Select()
由于某些其他原因返回,例如我上面的预感)。这可能会导致写入操作阻塞,并且可能是使用多个套接字操作时出现延迟的原因
最后,您可以在设置标志后立即跳出readyToWrite
循环。更好的是,您可以将其重新编码为:
bool readyToWrite = writelist.Any();
但我仍然建议您将其替换为writelist
上的foreach
循环:
foreach (Socket sock in writelist)
{
// do stuff
}
您的客户机代码是什么样子的
通常,我会说,由于您正在运行,您只在本地发送消息,因此您看到的行为几乎肯定是由Nagle的算法引起的,但设置NoDelay属性会禁用这一点。我的错误,似乎是由于最后的阻塞读取问题。TCP承诺将按顺序交付;建议至少有一个错误。只是一个快速的观察!订购可能不正确,可能只是看起来不正确,但主要问题是延迟!谢谢,但问题并不是真正的顺序,当他们通过时,这是正确的,这是巨大的30秒延迟的问题。你将不得不更好地记录网络特性。在你的帖子中没有任何东西不表明这是一个简单的硬件问题。但是如果这是一个硬件问题,那么从我的应用程序获得的初始消息如何?似乎只有当我尝试快速连续发送多条消息时,问题才会出现。这也是在一台机器上运行的,通过本地主机连接,因此不太可能与硬件相关。请务必在问题中指出这一点,这并不明显。消息实际上是在本地主机上发送的,因为它是在同一台机器上接收它们的另一个可执行文件。所以不能使用Wireshark。然而,我使用了一个localhost跟踪工具,正如我所说,我发现另一端正在接收该级别的消息,但是select返回并说没有什么可读的…而且,客户机代码是许多其他应用程序正在使用的成熟代码。所以我很有信心这一方是好的。而select最终发现了一些东西需要阅读,这只是del
bool readyToWrite = writelist.Any();
foreach (Socket sock in writelist)
{
// do stuff
}