我发现使用EndAccept传输初始数据是可能的。
这是来自文档:
EndAccept(Byte[],IAsyncResult(
异步接受传入连接尝试并创建处理远程主机通信的新Socket对象。这种方法返回包含传输的初始数据的缓冲区。C#
如何发送此初始字节?BeginConnect没有给我这个选项。我还能用别的方法吗?
使用.NETSocket
API时,请务必记住,此API不是.NET本机的。它是Windows Winsock 2 API的包装器,该API本身是原始Berkeley套接字API的Windows实现。这意味着在底层网络级别上可能存在.NET API不一定公开的功能。
此外,重要的是要记住,Socket
类提供了多种方法来完成相同的任务。特别是,Socket.Connect()
方法并不是唯一可用于创建连接的机制。还有一种Socket.ConnectAsync()
方法,它使用SocketAsyncEventArgs
为套接字操作(包括连接请求(提供状态,并且这种数据结构确实为请求连接的客户端提供了一种方式,以便也提供要发送的数据缓冲区。
即使没有Socket
方法,远程端点也可能不会使用.NET的API进行连接请求。其他套接字API,如Winsock 2中的WSAConnect()
函数,为客户端提供了一种机制,以包括要与连接请求一起传输的数据缓冲区。
我怀疑你是否会在另一个答案所描述的场景中发现这些数据。即,如果客户端将连接请求与任何实际的发送操作分开,则随后发送的数据将不会包含在连接请求中。这是因为客户端在连接请求完成之前无法在套接字上发送数据,而在服务器调用EndAccept()
之前则无法发送数据。与EndAccept()
一起交付的任何数据都必须作为原始连接请求的组成部分提供。
同步Socket.Connect()
方法没有提供这样做的方法,这是正确的,但还有其他可用的连接机制,包括Socket.ConnectAsync()
,以及非.NET套接字API,它们确实允许将数据缓冲区作为连接请求的一部分。这些数据将作为EndAccept()
方法调用的一部分由服务器接收。
我相信,如果您使用等待发送初始数据块的两个重载之一调用BeginAccept,那么相应的EndAccept将提供该数据块。如果调用该重载,则意味着在服务器端,接受客户端的API调用直到客户端发送了一些数据才完成。我想这在你的服务器代码中更有效,这样你就不会醒来,直到你接受的客户端有一些有用的数据。这可以节省大规模服务器中的上下文切换,并提高效率。
如果您只是调用BeginAccept的重载,而不是请求等待初始数据,那么相应的EndAccept将不会提供任何初始传输的数据。
这一点在AcceptEx(BeginAccept内部调用的函数(的文档中显而易见,摘录如下:
如果提供了接收缓冲区,则在接受连接并读取数据之前,重叠操作不会完成。
所以你的问题"我如何发送这个初始字节?"的答案从技术上讲就是让客户端"发送"。