【问题标题】:TCP C# Server Python Client cannot communicateTCP C# 服务器 Python 客户端无法通信
【发布时间】:2017-01-26 12:38:38
【问题描述】:

我正在编写一些套接字服务器、客户端应用程序,但我遇到了一个大问题。我的目标是在 C# 中创建一个异步服务器应用程序,并在 python 中创建一个基本客户端应用程序。当我遵循简单的示例时,两个程序都可以工作。但是,当我编写一个异步服务器时,使用从客户端 APP 发送的 readwrite 处理程序消息,它不起作用。

这是我正在使用的示例服务器代码。

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

这是一个简单的测试客户端的python代码

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 上插入了一些调试代码,我看到该例程被调用,但它不会将接收到的数据作为消息处理。它似乎没有端点。

我们将不胜感激任何想法或解决方案。

【问题讨论】:

    标签: c# python tcpclient asyncsocket


    【解决方案1】:

    您的ReadCallback 忽略了bytesRead == 0 时的情况,这意味着客户端停止发送数据。如果您的 Python 代码实际上是在没有 "&lt;EOF&gt;" 的情况下发送 "data",那么您的连接就会被 C# 服务器忘记。


    关于您的 C# 代码,您可以改进以下几点:

    • 使用ManualResetEventSlim,速度更快,不使用操作系统句柄(除非你实际使用WaitHandle属性)

    • 您应该在AcceptCallback 中处理来自EndAccept 的异常,在ReadCallback 中处理来自EndReceive 的异常,并可能改进SendCallback 中的异常处理

    • 您每次都在ReadCallback 中从StringBuilder 创建一个字符串,这完全违背了使用StringBuilder 的目的;您应该解析从Encoding.ASCII.GetString 获得的每个字符串以依次搜索每个字符&lt;EOF&gt;

     

    // 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
        // ...
    }
    

    【讨论】:

      【解决方案2】:

      不是C# 的专家,但我认为您对Python 程序有疑问。

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

      您正在尝试打印未定义的data。因此,except 部分将被执行(如果存在)。然后,程序结束,socket 关闭。

      【讨论】:

      • 如果您将except 放入try/finally 块中,是否会出现错误?
      猜你喜欢
      • 2016-02-15
      • 2012-04-19
      • 1970-01-01
      • 2013-12-14
      • 1970-01-01
      • 1970-01-01
      • 2018-01-03
      • 1970-01-01
      相关资源
      最近更新 更多