【问题标题】:C# .Net Socket Server ClientC# .Net 套接字服务器客户端
【发布时间】:2015-09-07 17:26:47
【问题描述】:

我对 C# 中的 .Net 套接字有一点问题。 我编写了一个使用 TCP 的客户端和一个服务器。

当客户端打开时,它会向服务器发送一个握手。服务器回答它的状态(客户端存在,客户端接受,...)。之后,应用程序发送一个 getdata-request,放弃连接并监听服务器的“响应”。现在,服务器与客户端建立连接并发送客户端所需的所有数据。

代码和其他一切都有效,但问题是:

在我们公司的测试服务器上它工作正常,在实时服务器上只有握手工作。之后,客户端不再收到任何数据。 Serverapplication 在两台服务器上都是一样的。

我以为问题是由某些防火墙引起的(服务器想与客户端建立 tcp 连接 -> 不好),但系统管理员说没有防火墙可以阻止。

现在我正在寻找一种不需要太多时间和代码更改的(“便宜”)解决方案。如果有人知道如何从理论上解决这个问题,那就太好了。

顺便说一句:除了运行服务器应用程序之外,我不能在实时服务器上做任何事情。我无法在此服务器上进行调试。

我无法发布我的所有代码,但如果您需要查看其中的特定部分,请索取。

---编辑---

客户端-服务器通信

1) 客户端启动
客户端发送握手(新的 tcp 连接)
2)服务器验证握手并保存IP
服务器以其客户端状态响应(相同的 tcp 连接)
3) 客户端确认此响应并放弃此连接
客户端发送 getdata-request(新的 tcp 连接)
客户端也放弃了这个 tcp 连接
4) 服务器接收getdata-request,在主库中收集需要的数据
服务器将所有收集到的数据发送给客户端(多个 tcp 连接)
5) 客户端接收所有数据并将其显示在其 GUI 中(多个 tcp 连接和数据的顺序通过使用 AutoResetEvents 和要发送的套接字计数来保持)

这是我的代码的主要部分。到目前为止,它还不是最好的,但我猜它是为我写的。第一步、第二步和第三步按预期工作。数据的处理也很好。 我忘记提及的另一件事是该解决方案使用两个端口“16777”和“16778”。一个接收/收听,一个发送。 我的代码基于异步 serverclient 的 MSDN 示例。

发送握手(和获取数据请求)

    public void BeginSend(String data)
    {
        try
        {
            StateObject state = new StateObject();
            state.workSocket = sender;

            byte[] byteData = Encoding.UTF8.GetBytes(data);

            sender.BeginSend(byteData, 0, byteData.Length, 0,
                new AsyncCallback((IAsyncResult e) =>
                {
                    Socket socket = (Socket)e.AsyncState;
                    SocketBase.StateObject stateObject = new SocketBase.StateObject();
                    stateObject.workSocket = socket;
                    socket.BeginReceive(stateObject.buffer, 0, 256, SocketFlags.None, new AsyncCallback(this.ReadCallback), (object)stateObject);

                }), sender);

            sender = RetrieveSocket(); //Socketreset

            Thread.Sleep(100);
        }
        catch /*(Exception e)*/
        {
            //--
        }
    }

服务器监听器

    public void StartListening()
    {
        listener = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);

        // Bind the socket to the local endpoint and listen for incoming connections.
        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(System.Int32.MaxValue);

            while (true)
            {
                // Set the event to nonsignaled state.
                allDone.Reset();

                // Start an asynchronous socket to listen for connections.
                listener.BeginAccept(
                    new AsyncCallback(AcceptCallback),
                    listener);

                // Wait until a connection is made before continuing.
                allDone.WaitOne();
            }

        }
        catch (Exception e)
        {
             //--
        }
    }

    public void AcceptCallback(...);
    public void ReadCallback(...);

套接字发送

    private void Send(Socket handler, String data)
    {
        Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
        // Convert the string data to byte data using ASCII encoding.
        byte[] byteData = Encoding.UTF8.GetBytes(data);

        // Begin sending the data to the remote device.
        t.BeginSend(byteData, 0, byteData.Length, 0,
            new AsyncCallback(SendCallback), t);
    }

Socket发送所有数据部分(getdata-request的回答| socToHandle应该是getdata-request的上一个连接的socket)

    private void SendAllData(Socket socToHandle, string PakContent)
    {
        #region IsThereADatetime? //Resolve a given datetime

        #region GiveClientNumberOfPackets //Send the client info about how much he has to receive (See line below)

            Send(socToHandle, "ALERT#TASKCOUNT;OPT-" + GetBestDate(dateStart) + EndSocket); 


        #region #SendResouces
        #region #SendGroups
        #region #SendTasks
    }

查看我的旧代码我有一个想法 =>

我能否通过更改通过同一连接发送所有内容:

Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);

(它创建一个新连接)到使用相同连接的东西? 如果那行得通,我该怎么做? 客户端的侦听器部分是否仍会收到单个数据包?

【问题讨论】:

  • 假设系统管理员在说谎。尝试在端口上使用technet.microsoft.com/en-us/sysinternals/jj729731.aspx 运行您的服务器并测试连接。上传尝试 ping 您的客户端 IP 的代码版本。双方也应始终测试防火墙/连接问题并记录它们。
  • 您不必向我们展示“我的所有代码”——事实上,这会适得其反。 有用的是您创建一个MCVE
  • TCP 实现的一个常见错误与接收流的处理有关。接收过程必须考虑到发送请求可能在不同的块中被接收。需要使用 Length-value 方法或分隔符来封装发送数据,例如STX 和 ETX。
  • 您似乎因为网络路由问题而放弃了。只是解决问题。显然,代码可以在您的机器上运行。 (不过,关闭这个问题,因为这里没有足够的信息来回答。这似乎是一个路由问题,仅此而已。)
  • 我很确定您的问题出在ReadCallback 代码中。似乎您忽略了消息帧(您没有发送字符串的长度,也没有终止符;但是如果没有ReadCallback 代码就不可能确定)- TCP 是一个流,而不是一堆的消息。 Windows 以完全不同的方式处理本地 TCP,这通常会导致应用程序在 localhost 上(大部分)正常工作,但在通过真实网络连接进行测试时完全失败。互联网交流往往会暴露更多问题。

标签: c# .net sockets tcp


【解决方案1】:

服务器及其环境已配置为正确处理传入请求。客户端通常位于路由器后面,默认情况下,这使它们无法接收来自网络外部的传入连接(一件好事)。

要启用传入连接,您可以将路由器配置为将特定端口号的所有请求转发到您的计算机。但是,您网络上的其他任何人都无法运行该客户端。

这就是为什么在典型的多客户端-单服务器环境中,客户端进行所有连接,而只有服务器需要对网络环境进行任何更改。

我不知道您为什么选择从服务器端连接到客户端,但我强烈建议您不要这样做 - 任何使用这种机制的廉价解决方案最终都可能变得非常昂贵。

【讨论】:

  • 感谢您的建议,我以后肯定会这样做,但我现在没有时间重写我的所有代码。任何客户端和服务器之间都没有路由器,只有第 2 层交换机。
猜你喜欢
  • 2017-05-26
  • 2014-03-10
  • 2012-06-24
  • 1970-01-01
  • 2011-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
相关资源
最近更新 更多