【发布时间】:2015-09-07 17:26:47
【问题描述】:
我对 C# 中的 .Net 套接字有一点问题。 我编写了一个使用 TCP 的客户端和一个服务器。
当客户端打开时,它会向服务器发送一个握手。服务器回答它的状态(客户端存在,客户端接受,...)。之后,应用程序发送一个 getdata-request,放弃连接并监听服务器的“响应”。现在,服务器与客户端建立连接并发送客户端所需的所有数据。
代码和其他一切都有效,但问题是:
在我们公司的测试服务器上它工作正常,在实时服务器上只有握手工作。之后,客户端不再收到任何数据。 Serverapplication 在两台服务器上都是一样的。
我以为问题是由某些防火墙引起的(服务器想与客户端建立 tcp 连接 -> 不好),但系统管理员说没有防火墙可以阻止。
现在我正在寻找一种不需要太多时间和代码更改的(“便宜”)解决方案。如果有人知道如何从理论上解决这个问题,那就太好了。
顺便说一句:除了运行服务器应用程序之外,我不能在实时服务器上做任何事情。我无法在此服务器上进行调试。
我无法发布我的所有代码,但如果您需要查看其中的特定部分,请索取。
---编辑---
客户端-服务器通信
1) 客户端启动
客户端发送握手(新的 tcp 连接)
2)服务器验证握手并保存IP
服务器以其客户端状态响应(相同的 tcp 连接)
3) 客户端确认此响应并放弃此连接
客户端发送 getdata-request(新的 tcp 连接)
客户端也放弃了这个 tcp 连接
4) 服务器接收getdata-request,在主库中收集需要的数据
服务器将所有收集到的数据发送给客户端(多个 tcp 连接)
5) 客户端接收所有数据并将其显示在其 GUI 中(多个 tcp 连接和数据的顺序通过使用 AutoResetEvents 和要发送的套接字计数来保持)
这是我的代码的主要部分。到目前为止,它还不是最好的,但我猜它是为我写的。第一步、第二步和第三步按预期工作。数据的处理也很好。 我忘记提及的另一件事是该解决方案使用两个端口“16777”和“16778”。一个接收/收听,一个发送。 我的代码基于异步 server 和 client 的 MSDN 示例。
发送握手(和获取数据请求)
public void BeginSend(String data)
{
try
{
StateObject state = new StateObject();
state.workSocket = sender;
byte[] byteData = Encoding.UTF8.GetBytes(data);
sender.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback((IAsyncResult e) =>
{
Socket socket = (Socket)e.AsyncState;
SocketBase.StateObject stateObject = new SocketBase.StateObject();
stateObject.workSocket = socket;
socket.BeginReceive(stateObject.buffer, 0, 256, SocketFlags.None, new AsyncCallback(this.ReadCallback), (object)stateObject);
}), sender);
sender = RetrieveSocket(); //Socketreset
Thread.Sleep(100);
}
catch /*(Exception e)*/
{
//--
}
}
服务器监听器
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(System.Int32.MaxValue);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
//--
}
}
public void AcceptCallback(...);
public void ReadCallback(...);
套接字发送
private void Send(Socket handler, String data)
{
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.UTF8.GetBytes(data);
// Begin sending the data to the remote device.
t.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), t);
}
Socket发送所有数据部分(getdata-request的回答| socToHandle应该是getdata-request的上一个连接的socket)
private void SendAllData(Socket socToHandle, string PakContent)
{
#region IsThereADatetime? //Resolve a given datetime
#region GiveClientNumberOfPackets //Send the client info about how much he has to receive (See line below)
Send(socToHandle, "ALERT#TASKCOUNT;OPT-" + GetBestDate(dateStart) + EndSocket);
#region #SendResouces
#region #SendGroups
#region #SendTasks
}
查看我的旧代码我有一个想法 =>
我能否通过更改通过同一连接发送所有内容:
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
(它创建一个新连接)到使用相同连接的东西? 如果那行得通,我该怎么做? 客户端的侦听器部分是否仍会收到单个数据包?
【问题讨论】:
-
假设系统管理员在说谎。尝试在端口上使用technet.microsoft.com/en-us/sysinternals/jj729731.aspx 运行您的服务器并测试连接。上传尝试 ping 您的客户端 IP 的代码版本。双方也应始终测试防火墙/连接问题并记录它们。
-
您不必向我们展示“我的所有代码”——事实上,这会适得其反。 将有用的是您创建一个MCVE。
-
TCP 实现的一个常见错误与接收流的处理有关。接收过程必须考虑到发送请求可能在不同的块中被接收。需要使用 Length-value 方法或分隔符来封装发送数据,例如STX 和 ETX。
-
您似乎因为网络路由问题而放弃了。只是解决问题。显然,代码可以在您的机器上运行。 (不过,关闭这个问题,因为这里没有足够的信息来回答。这似乎是一个路由问题,仅此而已。)
-
我很确定您的问题出在
ReadCallback代码中。似乎您忽略了消息帧(您没有发送字符串的长度,也没有终止符;但是如果没有ReadCallback代码就不可能确定)- TCP 是一个流,而不是一堆的消息。 Windows 以完全不同的方式处理本地 TCP,这通常会导致应用程序在 localhost 上(大部分)正常工作,但在通过真实网络连接进行测试时完全失败。互联网交流往往会暴露更多问题。