C# 异步套接字:服务器因垃圾邮件而停止接收?

C# 异步套接字:服务器因垃圾邮件而停止接收?,c#,sockets,asynchronous,C#,Sockets,Asynchronous,所以我一直在为学校作业开发聊天信使应用程序,我遇到了一堵隐喻墙 该应用程序允许您通过用户名登录到服务器,您可以从该用户名开始与其他用户聊天 在大多数情况下,它是工作的,它连接并且您可以发送消息。但是,当您尝试发送连续消息时,服务器似乎忽略了数据(因为数据是由客户端发送的),即使套接字仍然连接。在收到来自客户端的另一条消息之前,它不会确认此消息 这是该问题的视频: 我真的目瞪口呆,不知道如何处理这一点,所以任何和所有的帮助是非常感谢,如果我的代码是必要的,我会张贴它只是告诉我 编辑:我知道这是非常

所以我一直在为学校作业开发聊天信使应用程序,我遇到了一堵隐喻墙

该应用程序允许您通过用户名登录到服务器,您可以从该用户名开始与其他用户聊天

在大多数情况下,它是工作的,它连接并且您可以发送消息。但是,当您尝试发送连续消息时,服务器似乎忽略了数据(因为数据是由客户端发送的),即使套接字仍然连接。在收到来自客户端的另一条消息之前,它不会确认此消息

这是该问题的视频:

我真的目瞪口呆,不知道如何处理这一点,所以任何和所有的帮助是非常感谢,如果我的代码是必要的,我会张贴它只是告诉我

编辑:我知道这是非常广泛的,我只是在寻找一些想法或方法,我可以尝试,希望让我走在正确的方向上

编辑2: 服务器接收代码段:

    private void OnReceive(IAsyncResult ar) //Used to interpret data sent to the Server
            {
                try
                {
                    //MessageBox.Show("Receiving!");
                    Socket clientSocket = (Socket)ar.AsyncState; //Pass socket through beginReceive
                    clientSocket.EndReceive(ar);   //Procedure complete

                    //Transform the array of bytes received from the user into an
                    //intelligent form of object Data
                    Data msgReceived = new Data(buffer);

                    //We will send this object in response the users request
                    Data msgToSend = new Data();

                    byte[] message;

                    //If the message is to login, logout, or simple text message
                    //then when send to others the type of the message remains the same
                    msgToSend.cmdCommand = msgReceived.cmdCommand;
                    msgToSend.strName = msgReceived.strName;

                    switch (msgReceived.cmdCommand)
                    {
                        case Command.Login:

                            //When a user logs in to the server then we add them to our
                            //list of clients

                            ClientInfo clientInfo = new ClientInfo();
                            clientInfo.socket = clientSocket;
                            clientInfo.strName = msgReceived.strName;

                            clientList.Add(clientInfo);
                            msgToSend.cmdCommand = Command.List; //Need to send back a list of clients
                            updateServer("<<<" + msgReceived.strName + " is now connected on: " + clientInfo.socket.LocalEndPoint + ">>>");
                            break;

                        case Command.Logout: //Currently not working

                            //When a user wants to log out of the server then we search for them 
                            //in the list of clients and close the corresponding connection

                            int nIndex = 0;
                            foreach (ClientInfo client in clientList)
                            {
                                if (client.socket == clientSocket)
                                {
                                    clientList.RemoveAt(nIndex);
                                    break;
                                }
                                ++nIndex;
                            }
                            clientSocket.Close(100);

                            updateServer("<<<" + msgReceived.strName + " has disconnected>>>");
                            msgToSend.cmdCommand = Command.List;
                            break;

                        case Command.Message:

                            //Set the text of the message that we will broadcast to desired user
                            updateServer(msgReceived.strMessage);
                            msgToSend.cmdCommand = Command.Message;
                            msgToSend.strMessage = msgReceived.strMessage;
                            msgToSend.strName = msgReceived.strName;
                            msgToSend.strCName = msgReceived.strCName; //the recievers name

                            break;

                        case Command.List:

                            break;
                    }

                    //Send the message back to the deisred client
                    if (msgToSend.cmdCommand == Command.Message)
                    {
                        message = msgToSend.ToByte();
                        foreach (ClientInfo client in clientList)
                        {
                            if (client.strName == msgReceived.strCName)
                            {
                                client.socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), client.socket);
                            }
                        }
                    }

                    //Send a list of clients back to the client
                    if (msgToSend.cmdCommand == Command.List)
                    {
                        foreach (ClientInfo client in clientList)
                        {
                            msgToSend.strMessage += client.strName + "*";
                        }
                        msgToSend.strName = null;
                        message = msgToSend.ToByte();
                        foreach (ClientInfo client in clientList)
                        {
                            client.socket.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(OnSend), client.socket);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Server - OnReceive", MessageBoxButtons.OK, MessageBoxIcon.Error);


  }
        }
客户端发送代码段:

//Invoked via chat clients and is used to send a message to the server
        public void chat_sendMessage(string name, string contact, string message)
        {
            try
            {
                Data msgToSend = new Data(); //New data structure
                msgToSend.cmdCommand = Command.Message; //Set command to Message as we are sending a message
                msgToSend.strName = name; //Set sender name to parameter value: name
                msgToSend.strMessage = message; //Set strMessage to parameter value: message
                msgToSend.strCName = contact;  //Set reciever Name to parameter value: contact

                byte[] b = msgToSend.ToByte(); //Turn data structure into byte array

                State.workSocket.BeginSend(b, 0, b.Length, SocketFlags.None, new AsyncCallback(OnSend), null);  //Send using asynchronous socket (State.workSocket)

                if (State.workSocket.Connected == false)
                {
                    MessageBox.Show("Connection Lost :(");
                }

                State.workSocket.BeginReceive(State.buffer,
                                      0,
                                      State.buffer.Length,
                                      SocketFlags.None,
                                      new AsyncCallback(OnReceive),
                                      State.buffer);   //Listen to incoming data, uses State.buffer to store data
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Login Client - Send Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
用于在服务器和客户端之间通信的数据结构:

enum Command
    {
        //Log into the server
        Login,
        //Logout of the server
        Logout,
        //Send a text message to all the chat clients     
        Message,
        //Get a list of users in the chat room from the server
        List,
        //Null Value
        Null
    }

    //The data structure by which the server and the client interact with 
    //each other
    class Data
    {
        //Default constructor
        public Data()
        {
            this.cmdCommand = Command.Null;
            this.strMessage = null;
            this.strName = null;
            this.strCName = null;
        }

        //Converts the bytes into an object of type Data
        public Data(byte[] data)
        {
            //The first four bytes are for the Command
            this.cmdCommand = (Command)BitConverter.ToInt32(data, 0);

            //The next four store the length of the name
            int nameLen = BitConverter.ToInt32(data, 4);

            //The next four store the length of the message
            int msgLen = BitConverter.ToInt32(data, 8);

            //The next four store the length of the client Name
            int cnameLen = BitConverter.ToInt32(data, 12);

            //This check makes sure that strName has been passed in the array of bytes
            if (nameLen > 0)
                this.strName = Encoding.UTF8.GetString(data, 16, nameLen);
            else
                this.strName = null;

            //This checks for a null message field
            if (msgLen > 0)
                this.strMessage = Encoding.UTF8.GetString(data, 16 + nameLen, msgLen);
            else
                this.strMessage = null;

            if (cnameLen > 0)
                this.strCName = Encoding.UTF8.GetString(data, 16 + nameLen + msgLen, cnameLen);
            else
                this.strCName = null;
        }

        //Converts the Data structure into an array of bytes
        public byte[] ToByte()
        {
            List<byte> result = new List<byte>();

            //First four are for the Command
            result.AddRange(BitConverter.GetBytes((int)cmdCommand));

            //Add the length of the name
            if (strName != null)
                result.AddRange(BitConverter.GetBytes(strName.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Length of the message
            if (strMessage != null)
                result.AddRange(BitConverter.GetBytes(strMessage.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Length of the Client Name
            if (strCName != null)
                result.AddRange(BitConverter.GetBytes(strCName.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Add the name
            if (strName != null)
                result.AddRange(Encoding.UTF8.GetBytes(strName));

            //Add the message text to our array of bytes
            if (strMessage != null)
                result.AddRange(Encoding.UTF8.GetBytes(strMessage));

            //And, lastly we add the Client Name to our array of bytes
            if (strCName != null)
                result.AddRange(Encoding.UTF8.GetBytes(strCName));

            return result.ToArray();
        }

        public string strName;      //Name by which the client logs into the room
        public string strMessage;   //Message text
        public string strCName;     //Name of the desired recipient
        public Command cmdCommand;  //Command type (login, logout, send message, etcetera)
    }
enum命令
{
//登录到服务器
登录,
//注销服务器
注销,
//向所有聊天客户端发送文本消息
消息
//从服务器获取聊天室中的用户列表
列表
//空值
无效的
}
//服务器和客户机与之交互的数据结构
//彼此
类数据
{
//默认构造函数
公共数据()
{
this.cmdCommand=Command.Null;
this.strMessage=null;
this.strName=null;
this.strCName=null;
}
//将字节转换为数据类型的对象
公共数据(字节[]数据)
{
//前四个字节用于命令
this.cmdCommand=(命令)BitConverter.ToInt32(数据,0);
//接下来的四个存储名称的长度
int nameLen=BitConverter.ToInt32(数据,4);
//接下来的四个存储消息的长度
int msgLen=BitConverter.ToInt32(数据,8);
//接下来的四个存储客户端名称的长度
int cnameLen=BitConverter.ToInt32(数据,12);
//此检查确保strName已在字节数组中传递
如果(名称>0)
this.strName=Encoding.UTF8.GetString(数据,16,nameLen);
其他的
this.strName=null;
//这将检查是否存在空消息字段
如果(msgLen>0)
this.strMessage=Encoding.UTF8.GetString(数据,16+nameLen,msgLen);
其他的
this.strMessage=null;
如果(cnameLen>0)
this.strCName=Encoding.UTF8.GetString(数据,16+nameLen+msgLen,cnameLen);
其他的
this.strCName=null;
}
//将数据结构转换为字节数组
公共字节[]ToByte()
{
列表结果=新列表();
//前四个用于命令
AddRange(BitConverter.GetBytes((int)cmdCommand));
//添加名称的长度
if(strName!=null)
AddRange(BitConverter.GetBytes(strName.Length));
其他的
result.AddRange(BitConverter.GetBytes(0));
//信息的长度
if(strMessage!=null)
AddRange(BitConverter.GetBytes(strMessage.Length));
其他的
result.AddRange(BitConverter.GetBytes(0));
//客户端名称的长度
if(strCName!=null)
AddRange(BitConverter.GetBytes(strCName.Length));
其他的
result.AddRange(BitConverter.GetBytes(0));
//添加名称
if(strName!=null)
AddRange(Encoding.UTF8.GetBytes(strName));
//将消息文本添加到字节数组中
if(strMessage!=null)
AddRange(Encoding.UTF8.GetBytes(strMessage));
//最后,我们将客户端名称添加到字节数组中
if(strCName!=null)
AddRange(Encoding.UTF8.GetBytes(strCName));
返回result.ToArray();
}
public string strName;//客户端登录文件室时使用的名称
公共字符串strMessage;//消息文本
公共字符串strCName;//所需收件人的名称
公共命令cmdCommand;//命令类型(登录、注销、发送消息等)
}

您没有使用
EndReceive
的返回值。它告诉您接收了多少字节。请注意,TCP不保留消息。您的协议必须产生一种将它们分开的方法。查看消息框架


您的代码是否可以允许逐字节接收所有数据,或者一次接收一小时的数据?它必须是。

您能分享一些用于阅读/发送邮件的代码片段吗?你能将这种行为提取到一个示例程序中吗?@Jeroenvanevel嘿,我用一些相关的片段更新了我的问题(抱歉,它们太长了)。不幸的是,我已经能够在一个示例程序中复制该问题,它似乎是我的聊天messenger所独有的:(我已经添加了用于在客户端和服务器之间读/写消息的数据标准,它说明了字节长度以及所有不确定这是否是您的意思的内容。很抱歉不知道。您的代码是否能够容忍逐字节接收所有数据?如果Receive每次返回一个字节,您的代码是否工作?@usr+1因为,如果它可以不,它将永远不可靠。@usr我实际上不确定我将如何设置这样的测试,是否有任何示例项目在某处?
enum Command
    {
        //Log into the server
        Login,
        //Logout of the server
        Logout,
        //Send a text message to all the chat clients     
        Message,
        //Get a list of users in the chat room from the server
        List,
        //Null Value
        Null
    }

    //The data structure by which the server and the client interact with 
    //each other
    class Data
    {
        //Default constructor
        public Data()
        {
            this.cmdCommand = Command.Null;
            this.strMessage = null;
            this.strName = null;
            this.strCName = null;
        }

        //Converts the bytes into an object of type Data
        public Data(byte[] data)
        {
            //The first four bytes are for the Command
            this.cmdCommand = (Command)BitConverter.ToInt32(data, 0);

            //The next four store the length of the name
            int nameLen = BitConverter.ToInt32(data, 4);

            //The next four store the length of the message
            int msgLen = BitConverter.ToInt32(data, 8);

            //The next four store the length of the client Name
            int cnameLen = BitConverter.ToInt32(data, 12);

            //This check makes sure that strName has been passed in the array of bytes
            if (nameLen > 0)
                this.strName = Encoding.UTF8.GetString(data, 16, nameLen);
            else
                this.strName = null;

            //This checks for a null message field
            if (msgLen > 0)
                this.strMessage = Encoding.UTF8.GetString(data, 16 + nameLen, msgLen);
            else
                this.strMessage = null;

            if (cnameLen > 0)
                this.strCName = Encoding.UTF8.GetString(data, 16 + nameLen + msgLen, cnameLen);
            else
                this.strCName = null;
        }

        //Converts the Data structure into an array of bytes
        public byte[] ToByte()
        {
            List<byte> result = new List<byte>();

            //First four are for the Command
            result.AddRange(BitConverter.GetBytes((int)cmdCommand));

            //Add the length of the name
            if (strName != null)
                result.AddRange(BitConverter.GetBytes(strName.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Length of the message
            if (strMessage != null)
                result.AddRange(BitConverter.GetBytes(strMessage.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Length of the Client Name
            if (strCName != null)
                result.AddRange(BitConverter.GetBytes(strCName.Length));
            else
                result.AddRange(BitConverter.GetBytes(0));

            //Add the name
            if (strName != null)
                result.AddRange(Encoding.UTF8.GetBytes(strName));

            //Add the message text to our array of bytes
            if (strMessage != null)
                result.AddRange(Encoding.UTF8.GetBytes(strMessage));

            //And, lastly we add the Client Name to our array of bytes
            if (strCName != null)
                result.AddRange(Encoding.UTF8.GetBytes(strCName));

            return result.ToArray();
        }

        public string strName;      //Name by which the client logs into the room
        public string strMessage;   //Message text
        public string strCName;     //Name of the desired recipient
        public Command cmdCommand;  //Command type (login, logout, send message, etcetera)
    }