所以我一直在为学校作业开发一个聊天信使应用程序,我遇到了一个隐喻墙。
该应用程序允许您通过用户名登录服务器,您可以通过该用户名与其他用户进行聊天。
在大多数情况下它正在工作,它连接并且您可以发送消息但是当您尝试发送连续消息时,服务器似乎忽略了数据(因为它是由客户端发送的),即使套接字仍然连接。在从客户端收到另一条消息之前,它不会确认此消息。
这是该问题的视频:https://www.youtube.com/watch?v=8bUV6Ns02sY&feature=youtu.be
我真是傻眼了,不知道如何处理这个问题所以非常感谢所有的帮助,如果我的代码是必要的,我会发布它告诉我。
编辑:我知道这是非常广泛的我只是在寻找一些我可以尝试的想法或方法,希望能让我朝着正确的方向前进。
编辑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);
}
}
服务器发送代码段:
private void OnSend(IAsyncResult ar) //Callback for BeginSend
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndSend(ar); //Procedure Complete
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None,
new AsyncCallback(OnReceive), client); //Listens for more commands
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Server - OnSend", 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)
}
答案 0 :(得分:1)
您没有使用EndReceive
的返回值。它告诉你收到了多少字节。请注意,TCP不会保留消息。您的协议必须产生一种分离它们的方法。查看消息框架。
您的代码是否可以容忍所有数据逐字节接收或一小时数据一次接收?它必须。