2009-11-24 70 views
0

我在C#中創建套接字服務器,並在PHP中創建客戶端。客戶端和服務器之間的會話是這樣的:C#套接字問題

  1. 客戶端連接
  2. 服務器發送歡迎消息
  3. 客戶端發送數據
  4. 服務器發送響應
  5. (重複步驟3 - 4,直到客戶端斷開連接)

它一直工作到第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); 

回答

5

你從套接字讀取直到所有數據已被讀取 - 意思是「直到套接字關閉之前的所有數據」。您的PHP客戶端正在寫入數據,但未關閉套接字 - 所以服務器正在等待。

TCP套接字提供了一個的數據。沒有關於「當前消息的結束」的概念,它看起來像你想要的。

處理這種情況的三種方法通常是:

  • 一個消息分隔符(例如,換行)
  • (就在消息本身之前的消息中的字節數)的消息長度的前綴
  • 使用爲每個請求/響應對不同的連接

可以潛在地使用的讀出以超時,並且假設如果你在過去的5秒內沒有看到更多的數據,那麼你已經得到了整個信息 - 但這很脆弱,效率低下,而且通常是一個糟糕的主意。

+0

這解釋了很多!我將如何實現一個方法,從套接字讀取,直到達到某個特定的分隔符(讓它成爲換行符或其他內容)? – Max 2009-11-24 12:12:16

+0

@Max:這不是特別容易,因爲你可能會得到比你想消費更多的數據,所以你必須在某個地方存儲。不過,只要將套接字的流封裝在StreamReader中並持續調用Read,然後查看緩衝區以查看您感興趣的字符是否存在。當你有一個多字符分隔符當然是更復雜... – 2009-11-24 12:15:51

+0

非常感謝Jon的解釋。這澄清了我的套接字服務器和客戶端的一些奇怪的行爲。 – Max 2009-11-24 13:18:28