Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.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#中套接字编程入门-最佳实践_C#_.net_Sockets - Fatal编程技术网

C#中套接字编程入门-最佳实践

C#中套接字编程入门-最佳实践,c#,.net,sockets,C#,.net,Sockets,我在这里看到了很多关于套接字的参考资料。我相信他们中没有人涉及我想知道的细节。在我的应用程序中,服务器执行所有处理并定期向客户端发送更新 这篇文章的目的是介绍开发套接字应用程序所需的所有基本思想,并讨论最佳实践。以下是几乎所有基于套接字的应用程序的基本情况 1-在套接字上绑定和侦听 我正在使用以下代码。它在我的机器上运行得很好。当我在真正的服务器上部署它时,是否需要注意其他事项 IPHostEntry localHost = Dns.GetHostEntry(Dns.GetHostName())

我在这里看到了很多关于套接字的参考资料。我相信他们中没有人涉及我想知道的细节。在我的应用程序中,服务器执行所有处理并定期向客户端发送更新

这篇文章的目的是介绍开发套接字应用程序所需的所有基本思想,并讨论最佳实践。以下是几乎所有基于套接字的应用程序的基本情况


1-在套接字上绑定和侦听

我正在使用以下代码。它在我的机器上运行得很好。当我在真正的服务器上部署它时,是否需要注意其他事项

IPHostEntry localHost = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint endPoint = new IPEndPoint(localHost.AddressList[0], 4444);

serverSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, 
                     ProtocolType.Tcp);
serverSocket.Bind(endPoint);
serverSocket.Listen(10);
2-接收数据

我使用了一个255大小的字节数组。所以当我接收超过255字节的数据时,我需要调用receive方法,直到我得到完整的数据,对吗?一旦我得到了完整的数据,我需要附加到目前为止收到的所有字节以获得完整的消息。对吗?还是有更好的方法

3-发送数据并指定数据长度

由于在TCP中无法找到要接收的消息的长度,因此我计划将该长度添加到消息中。这将是数据包的第一个字节。因此,客户机系统知道有多少数据可供读取

还有其他更好的方法吗

4-关闭客户端

当客户端关闭时,它将向服务器发送一条消息,指示关闭。服务器将从其客户端列表中删除客户端详细信息。以下是客户端用于断开套接字连接的代码(未显示消息传递部分)

有什么建议或问题吗

5-关闭服务器

服务器向所有客户端发送指示关闭的消息。每个客户端在收到此消息时都将断开套接字的连接。客户端将向服务器发送关闭消息并关闭。一旦服务器从所有客户端接收到关闭消息,它就会断开套接字并停止侦听。在每个客户端套接字上调用Dispose以释放资源。这是正确的方法吗

6-未知客户端断开连接

有时,客户端可能会在不通知服务器的情况下断开连接。我的计划是:当服务器向所有客户端发送消息时,检查套接字状态。如果未连接,请从客户端列表中删除该客户端,并关闭该客户端的套接字


任何帮助都会很好

由于这是“入门”,我的答案将是简单的实现,而不是高度可扩展的实现。在使事情变得更复杂之前,最好先对简单的方法感到舒服

1-绑定和聆听
您的代码在我看来很好,我个人使用:

serverSocket.Bind(new IPEndPoint(IPAddress.Any, 4444));
而不是走DNS路线,但我认为这两种方式都没有真正的问题

1.5-接受客户端连接
只是为了完整起见才提到这个。。。我假设您正在这样做,否则您将无法进入第2步

2-接收数据
我将使缓冲区略长于255字节,除非您可以预期所有服务器消息最多为255字节。我认为您需要一个可能大于TCP数据包大小的缓冲区,这样您就可以避免为了接收单个数据块而进行多次读取

我认为选择1500字节应该可以,或者甚至可以选择2048字节作为一个不错的整数

或者,您可以避免使用
byte[]
存储数据片段,而是将服务器端客户端套接字封装在
NetworkStream
中,封装在
binarydreader
中,这样您就可以从套接字直接读取消息的组件,而不用担心缓冲区大小

3-发送数据并指定数据长度
您的方法可以很好地工作,但它显然要求在开始发送数据包之前,很容易计算数据包的长度

或者,如果消息格式(其组件的顺序)的设计方式使客户端能够随时确定是否应该有更多的数据在后面(例如,代码0x01表示next将是int和字符串,代码0x02表示next将是16字节,等等)。结合客户端的
NetworkStream
方法,这可能是一种非常有效的方法

为了安全起见,您可能需要添加接收组件的验证,以确保只处理sane值。例如,如果您收到长度为1TB的字符串的指示,您可能在某个地方发生了数据包损坏,关闭连接并强制客户端重新连接并“重新启动”可能更安全。这种方法在发生意外故障时为您提供了非常好的全面行为

4/5-关闭客户端和服务器
就我个人而言,我会选择只
关闭
,而不发送进一步的消息;当一个连接关闭时,您将在连接另一端的任何阻塞读/写上获得一个异常,您必须满足该异常

由于您无论如何都必须满足“未知断开”的需求,才能获得一个健壮的解决方案,因此使断开变得更加复杂通常是毫无意义的

6-未知断开连接
我甚至不相信插座的状态。。。连接可能会在客户机/服务器之间的路径上的某个位置终止,而客户机或服务器都不会注意到

告诉意外中断的连接的唯一可靠方法是下次尝试沿连接发送内容时。在这一点上,如果连接出现任何问题,您将始终得到一个异常,指示失败

因此,检测所有意外连接的唯一简单方法是impleme
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 4444));
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 4444));
serverSocket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, 0);
serverSocket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)23, 10);
using (var stream = new NetworkStream(serverSocket)) {
   var buffer = new byte[MaxMessageLength];
   while (true) {
      int type = stream.ReadByte();
      if (type == BYE) break;
      int length = stream.ReadByte();
      int offset = 0;
      do
         offset += stream.Read(buffer, offset, length - offset);
      while (offset < length);
      ProcessMessage(type, buffer, 0, length);
   }
}
var sslStream = new SslStream(stream, false);
sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, true);
// receive/send data SSL secured