C# TCP服务器用于简单聊天

6

我正在使用微软提供的异步示例编写我的第一个TCP服务器。

https://msdn.microsoft.com/en-us/library/fx6588te(v=vs.110).aspx

我已经将示例中的所有内容都运行成功了。现在,我正在将其扩展为一个简单的聊天程序。但是,我在遵循该程序的步骤时遇到了困难(可能是因为它是异步的)。当收到消息时,它会回显到客户端并关闭套接字。我不知道它何时重新打开套接字。
public static void StartListening() {
        // Data buffer for incoming data.
        byte[] bytes = new Byte[1024];

        // Establish the local endpoint for the socket.
        // The DNS name of the computer
        // running the listener is "host.contoso.com".
        IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
        IPAddress ipAddress = ipHostInfo.AddressList[0];
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);

        // Create a TCP/IP socket.
        Socket 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(100);

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

                // Start an asynchronous socket to listen for connections.
                Console.WriteLine("Waiting for a connection...");
                listener.BeginAccept( 
                    new AsyncCallback(AcceptCallback),
                    listener );

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

        } catch (Exception e) {
            Console.WriteLine(e.ToString());
        }

        Console.WriteLine("\nPress ENTER to continue...");
        Console.Read();

    }

private static void SendCallback(IAsyncResult ar) {
        try {
            // Retrieve the socket from the state object.
            Socket handler = (Socket) ar.AsyncState;

            // Complete sending the data to the remote device.
            int bytesSent = handler.EndSend(ar);
            Console.WriteLine("Sent {0} bytes to client.", bytesSent);

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

        } catch (Exception e) {
            Console.WriteLine(e.ToString());
        }
    }

此外,不保持套接字开启是否属于正常情况?


你知道如何编写阻塞式回声服务器吗?如果是的话,那么你应该了解反应器和异步模式。 - John
以下是代码行:listener.Listen(100)。 - jdweng
这是糟糕的微软示例之一。这里的异步IO并不真正是异步的,因为它等待完成。毫无意义。 - usr
@usr,他们这样做非常误导人... - user3822370
1个回答

2
当接收到消息时,它会回显到客户端并关闭套接字。我没有看到它重新打开套接字的地方。
这是因为它不需要重新打开。通信已经完成,服务器接收到消息后发送回复并结束该连接。它只是继续在监听套接字上等待新的连接。您有一个 while (true) 循环,在 accept 调用中继续等待新的传入连接。每个新的客户端都会得到一个新的套接字。
此外,保持套接字开放不是一种正常情况吗?
是的,监听套接字仍然保持开放。它保持开放以便使用 accept 接受新的连接。
使用异步和等待编写回声服务器的更好方法可以在这里找到:Using .Net 4.5 Async Feature for Socket Programming

所以套接字仍然是打开的,但是与该客户端的连接已关闭?我想我的实际问题应该是,“保持与客户端的连接是正常的”,而不是套接字。 - user3822370
1
你完全理解错了。监听套接字处于监听状态,永远不会在真正的连接中使用。每当有一个传入连接时,会发生监听套接字被克隆成一个新的套接字,但这是一个服务套接字,它属于包含该服务套接字和连接套接字的套接字对。套接字对标识连接。监听套接字永远不是套接字对的一部分,因此没有连接与之相关联。它只用作建立连接的方式。 - Philip Stuyck
1
请参见我的答案:http://stackoverflow.com/questions/30054673/tcp-listener-and-client-listening-to-specfic-ip/30060384#30060384。如果对您有所帮助,请标记为有用或回答。 - Philip Stuyck
好的,你分享的帖子确实帮了我很多。所以我再试一次!保持服务套接字开启是正常的吗? :) - user3822370
1
您的示例代码中服务套接字已关闭:handler.Shutdown(SocketShutdown.Both); handler.Close(); 具有明确请求回复机制的Web服务器将关闭连接。回声服务器、时间服务器也是如此。但聊天系统通常会根据其实现方式保持套接字打开更长的时间。 - Philip Stuyck
那正是我想的。谢谢。 - user3822370

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接