C#客户端-服务器协议/模型问题

Asked
Viewd3436

2

我正在尝试从概念上讲解我用C#(客户端和服务器)编写的客户端-服务器套接字应用程序的模型。我的服务器需要一次处理多个客户端,最好一次处理多个客户端的请求。我已经设计出一个用于通信的容器,在该容器中,我将在每个消息的开头发送一个固定长度的标头,其中包含(除其他事项外)消息的长度。我在c#中具有套接字编程方面的经验,因此我对使用异步套接字感到很满意。

从概念上讲,我遇到的主要问题是我需要客户端和服务器都能够随时接收消息。客户端将建立连接,并保持“登录”状态(类似于IM客户端),并且它将需要在任意时间接收数据并在任意时间发出请求。作为协议的一部分,我还希望收到对每个请求的响应(从服务器到客户端,或者从客户端到服务器)。

如果可能,我希望能够使用单个插座。我相信我可以使用两个套接字来完成这项工作,一个用于发出服务器->客户端请求,另一个用于客户端->服务器请求,但是我不想处理两个端口/连接带来额外的麻烦。但是,我不确定使用单个套接字时如何管理发送请求和在它们可能被交错时如何获取响应。

在搜索中找不到相似服务器或客户端的任何示例。感谢任何提供想法的人。

2 个答案

2

如果您使用的是TCP,那么服务器端每个客户端都必须有一个套接字,并且必须有套接字来侦听连接。对于UDP,您可以使用一个套接字完成所有操作。无论如何,对您的一个UDP套接字或每个TCP客户端套接字执行以下操作:

始终有一个BeginReceive,当您发生必要的事件时(即用户按下按钮或出现一条消息,您需要做些事情),始终有BeginWrite

编辑:针对您的评论,我要处理的方式是在标头中包含请求ID。每当发送请求(来自任一端)时,都应为该消息提供唯一值。使用Dictionary<RequestId, RequestState>(使用适当的类型替换),查看传入的消息是否与预先存在的请求有关。此外,您可以指定所有设置了高位的ID是来自客户端的请求,清除了高位的ID是来自服务器的请求,以避免冲突:

 Server                      Client
Request 0x00 -------------> Starts processing

Starts processing <-------  (unrelated) Request 0x80

Request 0x00 complete <---- Sends response to 0x00

Sends response to 0x80 ---> Request 0x80 complete
 

这是AOL的OSCAR协议用于处理(可能是缓慢的)有状态请求的系统。

EDIT2:嗯,好的...您真的想阻止它吗?您可以做的是让一个单独的线程处理Send/Receive调用。该线程将通过线程安全的“发送消息”队列和类似的“已接收消息”伪队列与主线程进行通信。我将后者称为伪队列的原因是,您希望能够从队列中取出消息。主线程将一条消息放在发送队列上,然后在接收队列上阻塞。套接字线程每次更新接收队列时,主线程都会唤醒,并检查它是否需要该消息。如果是这样,它将花费(乱序)并完成所需的操作。如果消息还不存在,它将再次在队列中阻塞。当操作最终完成时,它将恢复正常操作,并从接收队列中按顺序获取消息并对其进行处理或执行其他任何操作。

这有意义吗?抱歉,这有点令人困惑...

  • 是的,这很有道理。谢谢您,对您有很大帮助!

    JarrodMay 20, 2009 13:54
  • 对不起,所有关于套接字的讨论都让我觉得您的问题就在那个水平上。此更新如何?

    Neil WilliamsMay 19, 2009 21:58
  • 是的。但是,假设服务器需要花费一定时间从客户端请求某些内容。同时,客户端向服务器请求某些东西。在服务器的BeginReceive中,我如何知道传入的数据是来自客户端的请求,还是对服务器请求的响应?这就是我在努力的目标。我有异步套接字的基础。谢谢。

    JarrodMay 19, 2009 21:46
  • 对不起,我很难回答我的问题……但这正是我一直在试图解决的问题。我曾考虑过使用请求ID和字典,但想知道如何实现一种方法来发出请求并阻塞直到结果出现(并返回结果),而在我的请求状态对象中不使用ResetEvent之类的东西。不好为每个请求创建那些请求吗?谢谢。

    JarrodMay 19, 2009 22:05
3

套接字是双向的。您只需要一个套接字即可在两个端点之间来回发送数据。但是在客户端上,您可能需要使一个线程不断从套接字读取数据,并通知某些组件或将其接收的数据排队,以便在其他地方处理该线程,而另一个线程正在通过同一套接字发送数据。这样,您就可以进行异步通信。

但是在服务器端,您需要打开一个ServerSocket,它将绑定到TCP端口并接受该端口上的连接。您接受的每个连接都是一个新的套接字。因此,每个客户端有一个套接字,每个客户端可能需要一个线程。

您需要为要通过套接字传递的消息建立协议。您可以酿造自己的协议,也可以查找自己的协议,具体取决于要执行的操作。通常,您将首先发送带有其余消息长度的两个或四个字节,因此,另一端知道从流中读取了那么多字节;这是一条消息。消息的开头通常是消息类型。在非常简单的情况下,您可以说“ 1”是客户端请求,“ 2”是服务器响应,“ 3”是客户端回显,“ 4”是服务器回显响应,“ 5”是服务器echo,“ 6”是客户端回显响应,等等。例如,通过这种方式,您接收到一条消息,对其进行解析,然后您就知道它是来自客户端的请求或对服务器发送的消息的响应。