代码之家  ›  专栏  ›  技术社区  ›  BMBM

C#插座问题

  •  0
  • BMBM  · 技术社区  · 15 年前

    我正在用C#创建一个套接字服务器,用PHP创建一个客户端。客户端和服务器之间的对话如下所示:

    1. 客户端连接
    2. 服务器发送欢迎消息
    3. 客户端发送数据

    它一直工作到步骤3。服务器接收来自客户端的数据。但是,客户端会一直等待,直到服务器发送响应并最终超时。

    以下是相关的C#代码:

    class Program
    {
        private const int CONNECT_QUEUE_LENGTH = 4;
    
        static void ListenForRequests()
        {
            Socket listenSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            listenSock.Bind(new IPEndPoint(IPAddress.Any, 9999));
            listenSock.Listen(CONNECT_QUEUE_LENGTH);
            listenSock.Blocking = true;
    
            byte[] data = new byte[1024];
    
            while (true)
            {
                Socket newConnection = listenSock.Accept();
                newConnection.Blocking = true;
    
                // Create new thread for each request
                var t = new Thread(() => new RequestHandler(newConnection));
                t.Start();
            }
        }
    }
    
    class RequestHandler
    {
        public RequestHandler(Socket socket)
        {
            Util.WriteToSocket("A message", socket);
            Console.WriteLine("Received: " + Util.ReadSocketToEnd(socket).Length);
            Util.WriteToSocket("Fin!", socket);
        }
    }    
    
    static class Util
    { 
        public static string ReadSocketToEnd(Socket newConnection)
        {
            var sb = new StringBuilder();
    
            byte[] data = new byte[1024];
            int receivedDataLength = newConnection.Receive(data);
    
            while (receivedDataLength > 0)
            {
                try
                {
                    sb.Append(Encoding.UTF8.GetString(data, 0, receivedDataLength));
                    receivedDataLength = newConnection.Receive(data);
                }
                catch (SocketException)
                {
                    break;
                }
            }
    
            return sb.ToString();
        }
    
        public static void WriteToSocket(string message, Socket client)
        {
            byte[] data = Encoding.UTF8.GetBytes(message);
            client.Send(data, SocketFlags.None);
        }
    }
    

    这是一个简单的PHP客户端,没有任何错误处理等:

    <?php
    
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    $result = socket_connect($socket, '127.0.0.1', 9999);
    
    print 'receiving: ' . chr(10);
    print socket_read ($socket, 10) . chr(10);
    print 'receive end' . chr(10);
    
    
    $message = str_repeat("Message to sent", 1000);
    socket_write($socket, $message, strlen($message));
    print 'message sent' . chr(10);
    
    
    print 'reading fin' . chr(10); // This is printed, but a response is never received
    print socket_read ($socket, 10) . chr(10);
    print 'fin read!' . chr(10);
    
    socket_shutdown($socket);
    
    1 回复  |  直到 15 年前
        1
  •  5
  •   Jon Skeet    15 年前

    您正在从插座读取数据,直到 全部的 数据已被读取-意思是“所有数据直到套接字关闭”。您的PHP客户端正在写入数据,但没有关闭套接字,因此服务器将永远等待。

    TCP套接字提供了 大量的数据。没有“当前消息的结尾”的概念,这是您想要的。

    通常有三种处理方法:

    • 消息长度前缀(消息本身之前消息中的字节数)
    • 对每个请求/响应对使用不同的连接

    可能使用带超时的读取,并假设如果在过去5秒钟内没有看到任何更多数据,那么您已经获得了整个消息-但这是脆弱的、低效的,通常是一个坏主意。