简体   繁体   中英

C# socket problem

I am creating a socket server in C# and a client in PHP. The conversation between client and server is something like this:

  1. client connects
  2. server sends welcome message
  3. client sends data
  4. server sends response
  5. (repeat step 3 - 4 until client disconnects)

It works until step 3. The data from the client is received by the server. However, the client waits forever until the server sends its response and eventually times out.

Here is the relevant C# code:

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);
    }
}

And here is the simple PHP client, without any error handling etc:

<?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);

You're reading from the socket until all the data has been read - meaning "all the data until the socket is closed". Your PHP client is writing data, but not closing the socket - so the server is waiting forever.

TCP sockets provide a stream of data. There's no concept of "the end of the current message" which is what it looks like you want.

The three ways of handling this are usually:

  • A message delimiter (eg a line break)
  • A message length prefix (number of bytes in the message just before the message itself)
  • Use a different connection for each request/response pair

You could potentially use a read with a timeout, and assume that if you haven't seen any more data in the last 5 seconds, you've got the whole message - but that's fragile, inefficient and generally a bad idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM