Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#Socket:如果在BeginReceive之前调用BeginSend怎么办?_C#_Sockets - Fatal编程技术网

C#Socket:如果在BeginReceive之前调用BeginSend怎么办?

C#Socket:如果在BeginReceive之前调用BeginSend怎么办?,c#,sockets,C#,Sockets,我使用了TCP ping/pong,但在尝试添加第二种数据类型后,我遇到了一种情况,即接收程序从未触发BeginReceive回调 代码是相同的,只是对于第二个(有问题的)数据类型,序列化是提前完成的。这使我相信问题可能在于第二种数据类型调用BeginSend的速度更快,可能在另一个程序调用BeginReceive之前 或者,我想知道数据大小是否存在差异 所以我对So的问题是:有没有可能先发送后接收是个问题?如果是,如何处理?如果没有,还会出什么问题 普通的 enum数据类型:字节{A,B}

我使用了TCP ping/pong,但在尝试添加第二种数据类型后,我遇到了一种情况,即接收程序从未触发
BeginReceive
回调

代码是相同的,只是对于第二个(有问题的)数据类型,序列化是提前完成的。这使我相信问题可能在于第二种数据类型调用
BeginSend
的速度更快,可能在另一个程序调用
BeginReceive
之前

或者,我想知道数据大小是否存在差异

所以我对So的问题是:有没有可能先发送后接收是个问题?如果是,如何处理?如果没有,还会出什么问题

普通的
enum数据类型:字节{A,B}
数据接收器
TcpListener\u listener=newtcplistener(IPAddress.Any,2323);
数据类型_expectedDataType;
构造函数(){u listener.Start();}
Connect(){u listener.BeginAcceptSocket(OnConnect,null);}
OnConnect(IAsyncResult结果)
{
_套接字=_listener.EndAcceptSocket(结果);
_socket.ReceiveTimeout=1000;
_socket.SendTimeout=1000;
_expectedDataType=数据类型.A;
如果(_socket.Connected)
接收数据();
其他的
Connect();
}
接收数据()
{
Log(“接收”+_expectedDataType+“数据”);
//编辑:问题在于长度参数有时比使用过的第一个长度参数长
_socket.BeginReceive(_-dataBuffer[(int)_-expectedDataType],0,_-dataBuffer[_-expectedDataType]。长度,SocketFlags.None,OnReceiveData,null);
//缓冲区阵列A为119,B为133
}
OnReceiveData(IAsyncResult结果)
{
var bytes=_socket.EndReceive(结果);
Log(“收到”+_expectedDataType+“数据”的“+字节+”字节”);
//…根据数据类型从缓冲区反序列化多个变量。。。
如果(_需要更新数据)
_expectedDataType=DataType.B;
其他的
_expectedDataType=数据类型.A
_BeginSend(新的[]{(字节)u expectedDataType},0,1,SocketFlags.None,OnSendRequest,null);
}
OnSendRequest(IAsyncResult结果)
{
var bytes=_socket.EndSend(结果);
Log(“发送”+_expectedDataType+“请求”+字节+“字节”);
接收数据();
}
数据发送器
TcpClient\u client=new TcpClient();
数据类型_expectedDataType;
OneNoterIPAddress(字符串ipAddress){u client.BeginConnect(ipAddress.Parse(ipAddress),2323,OnClientConnect,null);}
OnClient连接(IAsyncResult结果)
{
_客户端.EndConnect(结果);
_stream=_client.GetStream();
_expectedDataType=数据类型.A;
SendData();
}
SendData()
{
//…根据expectedDataType序列化到缓冲区中
//这就是A需要很长时间,而B几乎是瞬间的。。。
变量字节=_buffer[(int)_expectedDataType]。长度;
Log(“发送长度为“+字节+”字节的“+_expectedDataType+”数据”);
_stream.BeginWrite(_buffer[(int)_expectedDataType],0,字节,OnWrite,null);
}
OnWrite(IAsyncCallback)
{
_stream.EndWrite(结果);
Log(“已发送”+_expectedDataType+“数据,等待响应”);
_BeginRead(_响应,0,1,OnRead,null);
}
OnRead(IAsyncCallback)
{
var bytes=_stream.EndRead(结果);
Log(“收到”+_expectedDataType+“数据”的“+字节+”字节”);
_expectedDataType=(数据类型)u响应[0];
SendData();
}
如果我禁用
\u needToUpdateBData
,以便只发送
A
数据,则这两部分可以顺利地来回移动。如果
\u needToUpdateBData
设置为true,则发送方将卡在“已发送B数据,等待响应”上,接收方将卡在“正在接收B数据”上,这意味着从未触发
onreceivedata
回调

即使将Socket.ReceiveTimeout设置为1000ms,其左侧仍无限期挂起“接收B数据”

请注意,try/catch丢失了,因为我打算在使用重连接逻辑使事情复杂化之前让它来回工作(实际上,为了使本文更简洁,已经删除了几个)

是否可能先发送后接收是问题所在

不,TCP连接的一端永远无法确定另一端是否有挂起的读取。即使远程端想要发出读取命令,其线程也可能会被重新调度很长时间。TCP必须能够在没有此保证的情况下工作。这不可能是一个问题

var bytes = _socket.EndReceive(result);
Debug.Log("Received " + bytes + "bytes of " + _expectedDataType + " Data");

// ... Deserialize several variables from the buffer based on data type ...

这看起来像是一个经典的bug,您假设一个读取调用将返回您想要的所有数据。相反,它可以返回部分结果。您不可能使用单个读取调用进行反序列化,因此我假设这是一个典型错误的例子

超时不适用于异步IO(我不知道为什么,这很糟糕)。也许,您无论如何都不应该使用异步IO。我可以看出,因为您使用异步方式接受套接字纯粹是在浪费开发时间。这让我觉得您没有意识到在同步和异步IO之间做出决定

if (_socket.Connected)
连接之后,这怎么可能是错误的?毫无意义。在不了解其他源代码的功能的情况下,不要复制其他源代码。这是一种常见的反模式


插座很难安装正确。最好的选择通常是使用现成的东西,如WCF、HTTP、websockets等。

“这看起来像是一个典型的错误,您假设一个读取调用将返回您想要的所有数据…”我在其他SO回答中遇到了这一点。我可以确认在单次读取中每次都会接收到所有133个字节。无论如何,建议的解决方案是进行第二次读取,并期望结果为0,但我的下一个BeginRead上的回调从未被调用,因此无论如何我都无法从EndRead获得0。或者这个“错误”是由在读取之间执行发送触发的吗?
如果(\u socket.Connected)
打算处理