预:
客户端打开套接字以将数据发送到服务器:
private void Form1_Load(object sender, EventArgs e)
{
client = new TcpClient();
client.BeginConnect("127.0.0.1", 995, new AsyncCallback(ConnectCallback), client);
}
private void ConnectCallback(IAsyncResult _result) // it will send hello message from client
{
string data;
byte[] remdata = { };
IAsyncResult inResult = _result;
currentProcess = Process.GetCurrentProcess();
string currentProcessAsText = currentProcess.Id.ToString();
SetControlPropertyThreadSafe(proccessIdLabel, "Text", currentProcessAsText);
try {
sock = client.Client;
// send hello message
data = "Client with proccess id " + currentProcessAsText + " is connecting";
sock.Send(Encoding.ASCII.GetBytes(data));
SetControlPropertyThreadSafe(answersTextBox, "Text", answersTextBox.Text + "\n"+ GetCurrentTime() + " Connection established");
}
catch
{
SetControlPropertyThreadSafe(answersTextBox, "Text", answersTextBox.Text + "\n" + GetCurrentTime() + " Can't connect");
}
}
之后我有点击某个按钮的处理程序(发送消息):
private void SendButton_Click(object sender, EventArgs e)
{
try
{
string data;
sock = client.Client;
data = "Some text";
sock.Send(Encoding.ASCII.GetBytes(data));
}
catch
{
SetControlPropertyThreadSafe(answersTextBox, "Text", "Can't connect");
}
}
也是表单关闭发送服务器exit
命令的处理程序,因此他将停止此客户端的线程:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
sock.Send(Encoding.ASCII.GetBytes("exit"));
sock.Close();
}
catch
{
}
}
服务器侦听端口并处理消息:
private void Listeners()
{
Socket socketForClient = Listener.AcceptSocket();
string data;
int i = 0;
if (socketForClient.Connected)
{
string remoteHost = socketForClient.RemoteEndPoint.ToString();
Console.WriteLine(Message("Client:" + remoteHost + " now connected to server."));
while (true)
{
// буфер данных
byte[] buf = new byte[1024];
try
{
int messageLength = socketForClient.Receive(buf);
if (messageLength > 0)
{
byte[] cldata = new byte[messageLength];
socketForClient.Receive(cldata);
data = "";
data = Encoding.ASCII.GetString(cldata).Trim();
if (data.Contains("exit"))
{
socketForClient.Close();
string message = Message("Client:" + remoteHost + " is disconnected from the server (client wish).");
Console.WriteLine(message);
return;
}
else
{
Console.WriteLine(Message("Recevied message from client " + remoteHost + ":\n"));
Console.WriteLine(data);
Console.WriteLine("\nEOF\n");
}
}
}
catch
{
string message = Message("Client:" + remoteHost + " is disconnected from the server (forced close).");
Console.WriteLine(message);
socketForClient.Close();
return;
}
}
}
}
private void ServStart()
{
Listener = new TcpListener(LocalPort);
Listener.Start(); // начали слушать
Console.WriteLine("Waiting connections [" + Convert.ToString(LocalPort) + "]...");
for (int i = 0; i < 1000; i++)
{
Thread newThread = new Thread(new ThreadStart(Listeners));
newThread.Start();
}
}
因此,在服务器启动时,它会创建1000个线程,这些线程会侦听客户端消息。
问题:
我将描述一些情况:
服务器启动线程并准备接受客户端连接
连接正在建立。服务器说客户端连接在某个端口上。客户发送&#34;你好&#34;信息。服务器无法处理此问候消息。
按下按钮,客户端会将一些文本发送到服务器。服务器处理此消息。
按下按钮。客户发送&#34;一些文字&#34;再次。服务器无法处理该消息。
按下按钮。客户发送&#34;一些文字&#34;再次。服务器处理该消息。
如果我再次推,它显然不会处理它......
服务器日志:
为什么服务器接收/客户端只发送2条消息中的1条?是什么导致它?
当客户端表单关闭时,我也会向服务器发送exit
消息。我就此操作发送了exit
条消息。
情况如此:
我只是按下了按钮而服务器处理了它(因此服务器不会处理下一条消息)。
我关闭表单,发送消息,但客户端发送错误消息或服务器收到错误消息。
控制台中的情况:
您可以看到,当表单关闭且客户端发送exit
时,服务器处理了empty
消息。为什么呢?
服务器正常传递客户端exit
命令时的情况:
控制台:
所以在第二项客户端发出了hello消息,服务器无法处理它。在第3项客户端发送退出命令,服务器正确传递它。
主要问题:为什么服务器只处理来自客户端的2条消息中的1条?
另一点:我也发现,当客户端发送exit
数据时,服务器会收到exit\0\0\0\0\0\0\0\0\
(或更多或更少\0
个符号)。为什么呢?
好消息我认为,服务器接收或不接收消息。收到1条消息,1条消息未收到。这说明我缺乏知识,但不是随机错误。
答案 0 :(得分:2)
这么多错误。 :(
那就是说,我注意到的最大的就是这个:
int messageLength = socketForClient.Receive(buf);
if (messageLength > 0)
{
byte[] cldata = new byte[messageLength];
socketForClient.Receive(cldata);
data = "";
data = Encoding.ASCII.GetString(cldata).Trim();
首先,要了解在TCP中,您无法保证任何给定的接收操作将接收的字节数。无论远程端点如何发送数据,您都可以在单独的接收操作中一次接收所有数据,或仅接收部分数据。 TCP保证将在发送它们的相同顺序中接收字节,仅此而已。
但上述代码不仅没有考虑到这一点,而且完全错误。第一个操作中接收的字节数是在该操作中接收的字节数。但是您正在使用该数字,就好像它会告诉您有关下一次调用Receive()
时收到的字节数的信息。它什么都不做。同时,您忽略在第一次操作中收到的数据。
相反,您的代码应该更像这样:
int messageLength = socketForClient.Receive(buf);
if (messageLength > 0)
{
data = Encoding.ASCII.GetString(buf, 0, messageLength).Trim();
那仍然不太正确,因为你当然可以在Receive()
的调用中收到一条部分消息,或者甚至连接在一起的多条消息。但至少你可能会看到所有的文字。
此更改将解决您提出的具体问题。如果您无法确定如何解决其他错误,请随时发布简明,具体问题和代码示例以寻求帮助。有关更好地提出问题的方法的建议,请参阅https://stackoverflow.com/help/mcve和https://stackoverflow.com/help/how-to-ask。