2017-01-26 205 views
3

我正在寫一些套接字服務器,客戶端應用程序,我有一個主要問題。我的目標是在C#中創建一個異步服務器應用程序,並在Python中創建一個基本的客戶端應用程序。當我確實遵循簡單的例子,既有程序工作。但是當我編寫一個異步服務器時,readwrite處理程序消息是從客戶端APP發送的,它不起作用。TCP C#服務器Python客戶端無法通信

以下是我正在使用的示例服務器代碼。

using System; 
using System.Net; 
using System.Net.Sockets; 
using System.Text; 
using System.Threading; 

// State object for reading client data asynchronously 
public class StateObject 
{ 
// Client socket. 
public Socket workSocket = null; 
// Size of receive buffer. 
public const int BufferSize = 1024; 
// Receive buffer. 
public byte[] buffer = new byte[BufferSize]; 
// Received data string. 
public StringBuilder sb = new StringBuilder(); 
} 

public class AsynchronousSocketListener 
{ 
// Thread signal. 
public static ManualResetEvent allDone = new ManualResetEvent(false); 

public AsynchronousSocketListener() 
{ 
} 

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, 3333); 
    IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, 3333); 
    // 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(ipLocal); 
     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(); 

} 

public static void AcceptCallback(IAsyncResult ar) 
{ 
    // Signal the main thread to continue. 
    allDone.Set(); 

    // Get the socket that handles the client request. 
    Socket listener = (Socket)ar.AsyncState; 
    Socket handler = listener.EndAccept(ar); 

    // Create the state object. 
    StateObject state = new StateObject(); 
    state.workSocket = handler; 
    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); 
} 

public static void ReadCallback(IAsyncResult ar) 
{ 
    String content = String.Empty; 

    // Retrieve the state object and the handler socket 
    // from the asynchronous state object. 
    StateObject state = (StateObject)ar.AsyncState; 
    Socket handler = state.workSocket; 

    // Read data from the client socket. 
    int bytesRead = handler.EndReceive(ar); 
    Console.WriteLine("\n Enters(0)"); 
    if (bytesRead > 0) 
    { 
     Console.WriteLine("\n Enters(1)"); 
     // There might be more data, so store the data received so far. 
     state.sb.Append(Encoding.ASCII.GetString(
      state.buffer, 0, bytesRead)); 

     // Check for end-of-file tag. If it is not there, read 
     // more data. 
     content = state.sb.ToString(); 
     if (content.IndexOf("<EOF>") > -1) 
     { 
      // All the data has been read from the 
      // client. Display it on the console. 
      Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", 
       content.Length, content); 
      // Echo the data back to the client. 
      Send(handler, content); 
     } 
     else 
     { 
      Console.WriteLine("\n Detect"); 
      // Not all data received. Get more. 
      handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
      new AsyncCallback(ReadCallback), state); 
     } 
    } 
    Console.WriteLine("\n Enters(1)"); 

} 

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

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

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


public static int Main(String[] args) 
{ 
    StartListening(); 
    return 0; 
} 
} 

,這裏是一個簡單的測試客戶端

import socket 

HOST, PORT = "127.0.0.1", 3333 
data = "data" 
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

try: 
    sock.connect((HOST, PORT)) 
    sock.sendall(data) 
    print data 
finally: 
    sock.close() 

正如我插在服務器的ReadCallback一些調試代碼,我看到程序被調用的Python代碼,但它不處理收到的數據作爲消息。它似乎沒有一個端點。

任何想法或解決方案,將不勝感激。

回答

0

不是C#的專家,但我認爲您的Python程序有問題。

try: 
    sock.connect((HOST, PORT)) 
    sock.sendall("data") 
    print data 
finally: 
    sock.close() 

您正在試圖打印data,這是未定義的。因此,except部分將被執行(如果存在)。然後,程序完成,套接字被關閉。

+0

是啊,我應該更新的代碼只是一個職位不匹配。 – androidgame2014

+0

如果你把'except'放在'try/finally'塊中,你會得到一些錯誤嗎? – Fejs

1

當您的ReadCallback忽略bytesRead == 0時,表示客戶端停止發送數據。如果你的Python代碼實際上是在沒有"<EOF>"的情況下發送"data",那麼你的連接就被C#服務器所遺忘。


關於你的C#代碼中,有幾件事情,你可以改善:

  • 使用ManualResetEventSlim,它的速度更快,它不使用操作系統手柄(除非你實際使用的WaitHandle屬性)

  • 你應該處理來自EndAccept異常在ReadCallbackAcceptCallbackEndReceive,並可能改善異常的手凌SendCallback

  • 你在ReadCallback每一次,這是完全違反了使用StringBuilder而創建從StringBuilder串;你應該分析每個你Encoding.ASCII.GetString得到的字符串紛紛尋找每一個字符,<EOF>

 

// Add to StateObject 
public const string EOF = "<EOF>"; 
public int eofOffset = -1; 
public int searchOffset = 0; 

// In ReadCallback 
string data = Encoding.ASCII.GetString(state.buffer, 0, bytesRead); 
state.sb.Append(data); 
int o = state.searchOffset + state.eofOffset + 1; 
while (o < state.sb.Length) 
{ 
    if (state.sb[o] != StateObject.EOF[state.eofOffset + 1]) 
    { 
     state.eofOffset = -1; 
     state.searchOffset++; 
     o = state.searchOffset; 
    } 
    else 
    { 
     state.eofOffset++; 
     if (state.eofOffset == StateObject.EOF.Length) 
     { 
      break; 
     } 
     o++; 
    } 
} 

// Replace this: 
//content = state.sb.ToString(); 
//if (content.IndexOf("<EOF>") > -1) 
// with this: 
if (state.eofOffset == StateObject.EOF.Length) 
{ 
    // Here is a good place to turn the StringBuilder into a string 
    // Perhaps truncate data to send back up to state.searchOffset 
    // ... 
}