C#

时间:2017-10-24 12:11:54

标签: c# .net sockets tcp

我有基于C#的Windows服务,它使用TCP端口通过Web连接到多个客户端。服务器具有静态IP,可帮助客户端定位服务器。我在这里发布了代码。

TcpListener tcp = new TcpListener(ipAddr, portNo);

tcp.Start();

listening = true;

while (listening)
{
    Socket mySocket = null;

    // Blocks until a client has connected to the server 
    try
    {
        mySocket = tcp.AcceptSocket();
        Thread.Sleep(500);

        byte[] bReceive = new byte[1024 * 1024 * 2];
        int i = mySocket.Receive(bReceive);
        byte[] databyte = new byte[i];

        for (int j = 0; j < i; j++)
        {
            databyte[j] = bReceive[j];
        }

        Analysis(databyte, mySocket);
    }
    catch (Exception exc)
    {
        logger.Error(exc);
    }
}

listening = false;
tcp.Stop();

有时我会收到这两个错误之一,即关闭连接并且所有客户端都断开连接:

  1. 远程主机强行关闭现有连接 System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags).

  2. 已建立的连接已被主机上的软件中止

    System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)

  3. 这些错误不是定期的,但会导致所有客户端出现时断开连接。该服务连接到大约300个客户端。

    编辑1: 根据@Sean H的建议,我修改了代码以异步读取数据。以下是代码:

    Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
    private static Logger logger = LogManager.GetCurrentClassLogger();
    
    //constructor 
    public Server()
    {
        listener.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.5"), 9000));
        listener.Listen(300);
        listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
        //Console.Write("Server Running...\r\n");
    }
    
    public void OnConnectRequest(IAsyncResult ar)
    {
        Socket listener = (Socket)ar.AsyncState;
        Socket accepted = listener.EndAccept(ar);
        listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
        NewConnection(accepted);
    }
    
    //send a string message over a TCP socket 
    public void sendMSG(Byte[] bSendData, ref Socket mySocket)
    {
        //some code which sends data according to my protocol
        int numBytes = 0;
    
        try
        {
            if (mySocket.Connected)
            {
                if ((numBytes = mySocket.Send(bSendData, bSendData.Length, 0)) == -1)
                {
                    logger.Error("Socket Error: Cannot Send Packet (Custom Error by me)");
                }
                else
                {
                }
            }
            else
            {
                logger.Error("Link Failed - Socket closed (Custom Error by me)");
            }
        }
        catch (Exception exc)
        {
            logger.Error(exc);
        }
    }
    
    public void receiveMSG(ref Socket mySocket)
    {
        byte[] bReceive = new byte[1024 * 1024 * 2];
        int i = mySocket.Receive(bReceive);
        byte[] databyte = new byte[i];
    
        for (int j = 0; j < i; j++)
        {
            databyte[j] = bReceive[j];
        }
    
        Analysis(databyte, mySocket);
    }
    
    
    //function called whenever a NEW CLIENT is connected
    public void NewConnection(Socket sockClient)
    {
        //Console.WriteLine("user {0} has joined", sockClient.RemoteEndPoint);
        //byte[] msg = new byte[20];
        receiveMSG(ref sockClient);
        //sockClient.Receive(msg);
    }
    

    这在测试环境中非常有用。

    我没有在生产中部署它,原因是,服务器如何知道它收到的数据是否已完成,或者还有一部分字符串仍然要从客户端发送到服务器。在我将其部署到生产环境之前,我无法知道Windows服务的实际行为,因为我在测试环境中有4个客户端,而生产中有300个客户端。

    然而@Sean H的建议变得很好,因为现在服务器在处理来自客户端的请求之前不会被阻止。它正在同时收听多个客户。

    我对这种TCP / IP编程比较陌生,我的问题可能看起来很愚蠢......

1 个答案:

答案 0 :(得分:0)

我想我看到了你的问题。当您的Analysis(字节,套接字)方法正在运行时,您的服务器无法接受更多连接。从客户端接受套接字后,在完成工作并再次调用.AcceptSocket()方法之前,您不再侦听该端口。

相反,您应该将工作发送到异步方法,并在绑定当前客户端连接后再次开始侦听。这是你想要做的一个很好的例子。

https://docs.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-server-socket-example