入门socket编程在C#中 - 最佳实践 [英] Getting started with socket programming in C# - Best practices

查看:175
本文介绍了入门socket编程在C#中 - 最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过很多的资源在这里因此,关于插槽。我相信他们没有覆盖的,我想知道的细节。在我的应用程序,服务器做所有的处理和发送定期更新的客户端。

I have seen many resources here on SO about Sockets. I believe none of them covered the details which I wanted to know. In my application, server does all the processing and send periodic updates to the clients.

这个帖子目的是覆盖所有的开发套接字应用程序,并讨论了最佳做法时所需的基本思路。这里,你将与几乎所有基于socket的应用程序看到基本的东西。

Intention of this post is to cover all the basic ideas required when developing a socket application and discuss the best practices. Here are the basic things that you will see with almost all socket based applications.

1 - 绑定和监听套接字

我使用下面的code。它运作良好,我的机器上。我需要照顾别的事情,当我部署这是一个真正的服务器上?

I am using the following code. It works well on my machine. Do I need to take care about something else when I deploy this on a real server?

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个字节,我需要调用接收方法,直到我获得完整的数据,对不对?一旦我得到了充分的数据,我需要追加所有接收到的迄今为止获得的全部消息的字节数。那是对的吗?还是有更好的方法?

I have used a 255 sized byte array. So when I am receiving data which is more than 255 bytes, I need to call the receive method until I get the full data, right? Once I got the full data, I need to append all the bytes received so far to get the full message. Is that correct? Or is there a better approach?

3 - 发送数据和指定的数据长度

由于没有办法在TCP中找到消息的长度来接收,我打算的长度添加到消息。这将是该分组的第一字节。因此,客户端系统知道如何可以读取大量数据。

Since there is no way in TCP to find the length of the message to receive, I am planning to add the length to the message. This will be the first byte of the packet. So client systems knows how much data is available to read.

任何其他更好的办法?

4 - 关闭客户端

当客户端关闭时,它会发送消息到服务器,指示密切。服务器将删除它的客户名单中的客户端的详细信息。以下是用于在客户端断开插座(消息传递部分未示出)。

When client is closed, it will send a message to server indicating the close. Server will remove the client details from it's client list. Following is the code used at client side to disconnect the socket (messaging part not shown).

client.Shutdown(SocketShutdown.Both);
client.Close();

任何建议或问题?

Any suggestions or problems?

5 - 关闭服务器

服务器发送消息,表示关闭所有客户端。每个客户端将断开插座,当它接收到该消息。客户端将发送关闭消息服务器和关闭。一旦服务器收到关闭消息的所有客户端,它断开插座和停止监听。调用的的Dispose 的每个客户端套接字以释放资源。那是正确的做法?

Server sends message to all clients indicating the shutdown. Each client will disconnect the socket when it receives this message. Clients will send the close message to server and close. Once server receives close message from all the clients, it disconnects the socket and stop listening. Call Dispose on each client sockets to release the resources. Is that the correct approach?

6 - 未知的客户端断开

有时候,一个客户可能断开而不通知服务器。我的计划来处理这个问题是:当服务器发送消息到所有客户端,检查端口状态。如果未连接,则删除该客户从客户端列表和关闭套接字为该客户端。

Sometimes, a client may disconnect without informing the server. My plan to handle this is: When server sends messages to all clients, check the socket status. If it is not connected, remove that client from the client list and close the socket for that client.

任何帮助将是巨大的!

推荐答案

由于这是入门我的回答会坚持用一个简单的实现,而不是一个高度可扩展的。这是最好的第一感觉舒服使事情变得更复杂之前,简单的方法。

Since this is 'getting started' my answer will stick with a simple implementation rather than a highly scalable one. It's best to first feel comfortable with the simple approach before making things more complicated.

1 - 绑定和听
您的code似乎没什么问题,我个人使用的:

1 - Binding and listening
Your code seems fine to me, personally I use:

serverSocket.Bind(new IPEndPoint(IPAddress.Any, 4444));

而不是去了DNS的路线,但我不认为这是一个真正的问题两种方式。

Rather than going the DNS route, but I don't think there is a real problem either way.

1.5 - 接受客户端连接
刚刚提到这一点,为了完整性的缘故......我假设你正在做这个,否则你不会得到第2步。

1.5 - Accepting client connections
Just mentioning this for completeness' sake... I am assuming you are doing this otherwise you wouldn't get to step 2.

2 - 接收数据
我会做缓冲有点超过255字节,除非你能指望所有的服务器消息是最多255个字节。我想你会希望有一个缓冲区,则可能会比TCP数据包大小这样就可以避免进行多次读取接收数据的单块。

2 - Receiving data
I would make the buffer a little longer than 255 bytes, unless you can expect all your server messages to be at most 255 bytes. I think you'd want a buffer that is likely to be larger than the TCP packet size so you can avoid doing multiple reads to receive a single block of data.

我说捡1500个字节应该是罚款,甚至可能在2048的一个不错的轮数。

I'd say picking 1500 bytes should be fine, or maybe even 2048 for a nice round number.

另外,也许你能避免使用字节[] 来存储数据片段,而是裹在的NetworkStream服务器端客户端套接字,包裹在一个 BinaryReader在,这样就可以读取你的信息的组件direclty从插座,而无需担心缓冲区的大小。

Alternately, maybe you can avoid using a byte[] to store data fragments, and instead wrap your server-side client socket in a NetworkStream, wrapped in a BinaryReader, so that you can read the components of your message direclty from the socket without worrying about buffer sizes.

3 - 发送数据,并指定数据长度
你的方法会工作得很好,但它显然需要,很容易计算出数据包的长度,启动发送前。

3 - Sending data and specifying data length
Your approach will work just fine, but it does obviously require that it is easy to calculate the length of the packet before you start sending it.

或者,如果您的消息格式(为了它的组件)被设计在一个方式,以便在任何时间在客户端将能够确定是否应该有以下更多的数据(例如,code 0x01表示下一个将一个int和一个字符串,code 0X02意味着明年将是16个字节,等等,等等)。结合在客户端的的NetworkStream 的办法,这可能是一个很有效的办法。

Alternately, if your message format (order of its components) is designed in a fashion so that at any time the client will be able to determine if there should be more data following (for example, code 0x01 means next will be an int and a string, code 0x02 means next will be 16 bytes, etc, etc). Combined with the NetworkStream approach on the client side, this may be a very effective approach.

为了安全起见,你可能需要添加接收部件的验证,以确保您只处理合理的值。例如,如果您收到的指示长度1TB的字符串,你可能有一个数据包损坏的地方,它可能是更安全的关闭连接,并强迫客户端重新连接,并重新开始。这种方法使你的情况下意外故障非常好的包罗万象的行为。

To be on the safe side you may want to add validation of the components being received to make sure you only process sane values. For example, if you receive an indication for a string of length 1TB you may have had a packet corruption somewhere, and it may be safer to close the connection and force the client to re-connect and 'start over'. This approach gives you a very good catch-all behaviour in case of unexpected failures.

4/5 - 关闭客户端和服务器
个人而言,我会选择只关闭没有进一步的消息;当连接被关闭,你将在你将不得不迎合连接的另一端得到任何阻拦的读/写一个例外。

4/5 - Closing the client and the server
Personally I would opt for just Close without further messages; when a connection is closed you will get an exception on any blocking read/write at the other end of the connection which you will have to cater for.

既然你已经满足未知断开反正得到一个强大的解决方案,使断开任何更复杂的是一般意义的。

Since you have to cater for 'unknown disconnections' anyway to get a robust solution, making disconnecting any more complicated is generally pointless.

6 - 未知断开
我不相信,即使端口状态......这是可能的连接到某个地方一起死的客户机/服务器之间的路径没有客户端或服务器无法看到。

6 - Unknown disconnections
I would not trust even the socket status... it is possible for a connection to die somewhere along the path between client / server without either the client or the server noticing.

唯一可以保证的方式来告诉大家,已意外死亡的连接是当你下次尝试的发送的沿着连接的东西。在这一点上,你总是会得到一个异常指示故障如果有什么出了毛病的连接。

The only guaranteed way to tell a connection that has died unexpectedly is when you next try to send something along the connection. At that point you will always get an exception indicating failure if anything has gone wrong with the connection.

其结果是,唯一的防呆的方法来检测所有意想不到的连接是实施的ping机制,其中,理想地在客户端和服务器将定期发送消息到另一端仅导致一个响应消息表明的ping接收

As a result, the only fool-proof way to detect all unexpected connections is to implement a 'ping' mechanism, where ideally the client and the server will periodically send a message to the other end that only results in a response message indicating that the 'ping' was received.

要优化了不必要坪,您可能希望只将在没有其他流量已收到来自另一端的时间固定金额(例如一个ping一个超时的机制,如果最后从服务器消息超过x秒的时候,客户端发送一个ping,以确保连接没有恕不另行通知去世)。

To optimise out needless pings, you may want to have a 'time-out' mechanism that only sends a ping when no other traffic has been received from the other end for a set amount of time (for example, if the last message from the server is more than x seconds old, the client sends a ping to make sure the connection has not died without notification).

更先进
如果你想要高可扩展性,你将不得不考虑异步方法为所有插座操作(接受/发送/接收)。这些都是开始/结束的变种,但他们有很多更复杂的使用。

More advanced
If you want high scalability you will have to look into asynchronous methods for all the socket operations (Accept / Send / Receive). These are the 'Begin/End' variants, but they are a lot more complicated to use.

我建议不要尝试,直到你有简单的版本和工作。

I recommend against trying this until you have the simple version up and working.

另外请注意,如果你不打算进一步扩展几十余个客户,这是不实际会成为一个问题,而不管。异步技术是真的只是如果你打算扩展到数千或数十万连接的客户端,而不是有你的服务器彻底死掉必要的。

Also note that if you are not planning to scale further than a few dozen clients this is not actually going to be a problem regardless. Async techniques are really only necessary if you intend to scale into the thousands or hundreds of thousands of connected clients while not having your server die outright.

我可能已经忘记了一大堆其他的重要建议,但是这应该是足以让你一个相当强大和可靠的执行入手

这篇关于入门socket编程在C#中 - 最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆