Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
能给我一些关于C#中基本异步套接字编程的建议吗?_C#_Asyncsocket - Fatal编程技术网

能给我一些关于C#中基本异步套接字编程的建议吗?

能给我一些关于C#中基本异步套接字编程的建议吗?,c#,asyncsocket,C#,Asyncsocket,我正在开发(或尝试开发)一个程序,它使用异步套接字在任何时候向服务器和客户端传递字符串 此程序要求连接到服务器的客户端不超过一个。我尝试过Socket编程,但我发现它会阻止程序,直到其中一个收到某些东西 因为我对异步套接字编程只有基本的了解,所以我只选择了我能找到的最简单的一个,或者至少是我能理解的最简单的一个 以下是我的服务器代码: public Socket g_server_conn; public byte[] g_bmsg; public bool check

我正在开发(或尝试开发)一个程序,它使用异步套接字在任何时候向服务器和客户端传递字符串

此程序要求连接到服务器的客户端不超过一个。我尝试过Socket编程,但我发现它会阻止程序,直到其中一个收到某些东西

因为我对异步套接字编程只有基本的了解,所以我只选择了我能找到的最简单的一个,或者至少是我能理解的最简单的一个

以下是我的服务器代码:

    public Socket g_server_conn;
    public byte[] g_bmsg;
    public bool check = false;  

    private void net_As_Accept(IAsyncResult iar)
    {
        Socket server_conn = (Socket)iar.AsyncState;
        g_server_conn = server_conn.EndAccept(iar);
        g_bmsg = new byte[1024];
        check = true;
        g_server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(net_As_Receive), g_server_conn);
    }

    private void net_As_Send(IAsyncResult iar)
    {
        Socket server_conn = (Socket)iar.AsyncState;
        server_conn.EndSend(iar);
    }

    private void net_As_Receive(IAsyncResult iar)
    {
        try
        {
            Socket server_conn = (Socket)iar.AsyncState;
            server_conn.EndReceive(iar);
            if (g_bmsg.Length != 0)
            {
                net_Data_Receive(Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));
                check = false;
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString(), "GG");
        }
    }

    public void net_Data_Send(string msg2snd) // Function for sending through socket
    {
        MessageBox.Show(msg2snd);
        byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg2snd);
        g_server_conn.BeginSend(byData, 0, byData.Length, SocketFlags.None, new AsyncCallback(net_As_Send), g_server_conn);
        g_server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(net_As_Receive), g_server_conn);
    }

    private void net_Data_Receive(string txt)
    {
        if (lblBuffer.InvokeRequired)
            lblBuffer.Invoke(new MethodInvoker(delegate { net_Data_Receive(txt); }));
        else
            lblBuffer.Text = txt;

        if (txt.StartsWith("&"))
        {
            // Do something              
        }
    }
这是我的客户代码:

    private void net_As_Connect(IAsyncResult iar)
    {
        try
        {
                Socket client_conn = (Socket)iar.AsyncState;
                client_conn.EndConnect(iar);
                g_bmsg = new byte[1024];
                check = true;
                string toSendData = "&" + net_Name;
                net_Data_Send(toSendData);
                g_client_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(net_As_Receive), g_client_conn);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString(), "GG");
        }
    }

    private void net_As_Send(IAsyncResult iar)
    {
        Socket client_conn = (Socket)iar.AsyncState;
        client_conn.EndSend(iar);
    }

    private void net_As_Receive(IAsyncResult iar)
    {
        if (g_bmsg.Length != 0)
        {
            net_Data_Receive(Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));
            check = false;
        }
    }

    public void net_Data_Send(string msg2snd)
    {
        byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg2snd);

        g_client_conn.BeginSend(byData, 0, byData.Length, SocketFlags.None, new AsyncCallback(net_As_Send), g_client_conn);
        g_client_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(net_As_Receive), g_client_conn);
    }

    private void net_Data_Receive(string txt)
    {
        if (lblBuffer.InvokeRequired)
            lblBuffer.Invoke(new MethodInvoker(delegate { net_Data_Receive(txt); }));
        else
            lblBuffer.Text = txt;

        if (txt.StartsWith("&"))
        {
            // Do Something              
        }
        else if (txt.StartsWith("$"))
        {
            // Do something Else
        }

    }
现在,客户端可以很好地连接到服务器。客户端甚至可以向服务器发送一个包含用户名的字符串,该字符串将显示在服务器上。然后,服务器向客户端发送其用户的名称,客户端接收并显示该名称。发送的内容都存储在标签(lblBuffer)中

但之后,假设我有以下代码:

    private void btnSendData_Click(object sender, EventArgs e)
    {
        string posMov = "Stuff to send";
        net_Data_Send(posMov);
    }
客户没有收到任何东西。在net_Data_Send(msg2snd)函数中放置一个消息框表明服务器实际上发送了消息。事实上,将消息框放在该函数中可以使它工作(客户端接收它),原因我不知道。由于我没有尝试将消息从客户端发送到服务器(客户端连接时的名称除外),因此我假设客户端在发送到服务器时也会遇到同样的问题

此外,当它确实发送第二条消息时(通过在net_Data_send函数中放置一个消息框),只有部分标签(lblBuffer)被覆盖。因此,如果我的名字是“Anon E.Moose”,服务器在客户端连接时发送,我尝试发送,比如说,“0.0”(通过按键),客户端上的标签将显示为“0.0n E.Moose”

我做错了什么?请帮我一下好吗


也许我在网络数据接收和网络数据发送方面有问题?

BeginReceive不只是在新数据包到达时调用它的回调(在您的例子中是字符串)。事实上BeginReceive或任何原始套接字方法以基于流的方式工作,而不是基于数据包。有关示例,请参见

您需要做的是,在“net_As_Receive”回调方法中(命名非常糟糕),您需要首先调用socket.EndRecieve(IAsyncResult),它反过来返回当前可用的总字节数。之后,您必须决定是否接收更多数据

例如:

private StringBuilder packetBuilder;
{ 
    if (packetBuilder == null)
        packetBuilder = new StringBuilder();

    // finalyze the receive
    int length = g_server_conn.EndReceive(iar);

    if (length != 0) 
    { 
        // get the total bytes received. Note that the length property is of that of the number of bytes received rather than that of the buffer
        packetBuilder.Append(Encoding.ASCII.GetString(g_bmsg, 0, length));

        net_Data_Receive(packetBuilder.ToString()); 
        check = false; 
    } 

    // receive the next part
    g_server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(net_As_Receive), g_server_conn);  
} 

注意,这个例子并不关心包。如果你幸运的话,它会起作用,但是有一个很好的变化,要么显示一个字符串的一部分,要么组合两个不同的字符串。一个好的实现将查找字符串结束,并仅显示该部分,同时缓冲其余部分,直到找到新的字符串结束。您还可以使用StreamReader使您的生活更加轻松

我认为您需要在客户端上再次调用BeginReceive,看起来您只调用了它一次,因此在它收到服务器名称后,它不再侦听来自服务器的任何数据

private void net_As_Receive(IAsyncResult iar)
{
    var bytesRead = g_client_conn.EndReceive(iar);


    if (bytesRead != 0)
    {
        net_Data_Receive(Encoding.ASCII.GetString(g_bmsg, 0, bytesRead));
        check = false;
    }

    g_client_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(net_As_Receive), g_client_conn);
}
另外,正如我在评论中提到的,使用bytesRead值来计算需要使用多少缓冲区


您需要确定从套接字接收到的数据是否为全部数据,或者是否需要读取更多数据以从另一端组成当前消息。

覆盖的问题是,您正在将缓冲区的内容从ascii字节转换为字符串,g_bmsg.Length将返回字节数组的长度,而不是接收调用放入其中的数据的当前长度。您需要存储实际读取的字节数,并使用它,谢谢。它现在可以接收消息了。虽然我还在做标签覆盖的事情。顺便说一下,我的C#中没有“var”。我想只有C#3.0版本才有。将其更改为“int”会弄糟什么吗?不,使用int:)对不起,现在习惯使用var了,这是第二天性!