[英]C# .NET socket tcp begin/endreceive client : endreceive reads all bytes, but in beginreceive, the buffer size changes on its own
so i have a server and client using the class Socket (on tcp).所以我有一个使用 Socket 类(在 tcp 上)的服务器和客户端。
I've been struggling with this problem for a few weeks, I've searched a lot but I don't understand how that problem is possible.我一直在为这个问题苦苦挣扎了几个星期,我搜索了很多,但我不明白这个问题是怎么可能的。 I've been watching debugger a lot, watching values of my variables but can't see where the problem is.
我一直在观察调试器,观察变量的值,但看不出问题出在哪里。
For example, the client sends 100 bytes, and the server receives them, proceeds them and send back 150 bytes.例如,客户端发送 100 个字节,服务器接收它们,处理它们并返回 150 个字节。 But, on client side, the buffer changes size each time the client receives a message (i don't know why, maybe because of beginreceive).
但是,在客户端,每次客户端收到消息时缓冲区都会改变大小(我不知道为什么,可能是因为 beginreceive)。
So, when the server sends these 150 bytes, the client beginreceive, but I see that the buffer size is 100 (same size as the previous message the client has sent).因此,当服务器发送这 150 个字节时,客户端开始接收,但我看到缓冲区大小为 100(与客户端发送的前一条消息的大小相同)。
And the client does "endreceive", and read 150 bytes (the right amount of bytes sent by server).客户端执行“接收”,并读取 150 个字节(服务器发送的正确字节数)。
When i want to get the string, i use an encoding function, the buffer containing message, and the number of bytes received.当我想获取字符串时,我使用编码函数、包含消息的缓冲区以及接收到的字节数。
So, i end up having a buffer of size of 100 bytes (wrong size) and the number of bytes read is 150 bytes (right amount).所以,我最终有一个大小为 100 字节(错误大小)的缓冲区,读取的字节数为 150 字节(正确数量)。
I've modified my code many times, tried to define "new byte[bufferSize]", but the problem stays the same.我已经多次修改我的代码,试图定义“新字节[bufferSize]”,但问题保持不变。
Sometimes, the client even receive message that the server has never sent!有时,客户端甚至会收到服务器从未发送过的消息! That's weird.
这很奇怪。 The client seems sometimes to receive bytes from the "server buffer" (i haven't found how to check it)
客户端有时似乎从“服务器缓冲区”接收字节(我还没有找到如何检查它)
public void InitializeReceive(Socket soc)
{
//bufferSize is fixed to 256
MyBuffer = new byte[bufferSize];
soc.BeginReceive(MyBuffer , 0, MyBuffer .Length,
SocketFlags.None, new AsyncCallback(Receiving), soc);
}
public void Receiving(IAsyncResult iar)
{
Socket tmp = (Socket)iar.AsyncState;
int received= tmp.EndReceive(iar);
if (received> 0)
{
//problem is here. MyBuffer has a size of 100 bytes, received is 150 bytes
string msg = Encoding.Unicode.GetString(MyBuffer, 0, received);
//next message
InitializeReceive(tmp);
}
}
i've tried checking heap stack, stuff like this too, but i don't really know how to diagnostic it.我试过检查堆堆栈,类似这样的东西,但我真的不知道如何诊断它。
The first messages between client and server are okay.客户端和服务器之间的第一条消息没问题。 But it becomes like this after a few exchanges, and the buffer that i fixed isn't full at all.
但是几次交换后就变成这样了,我修复的缓冲区根本就没有满。 The size of first messages were around 36 bytes, over 100 bytes, and so on.
第一条消息的大小约为 36 字节,超过 100 字节,依此类推。 It doesn't seem to be a problem of size here
这里好像不是大小问题
I don't even understand how it is possible.我什至不明白这怎么可能。 I hope someone has an explanation thank you !
希望有大神给个解释谢谢!
EDIT :编辑 :
So, as asked, I tried to make a minimal reproducible code.所以,正如所问,我试图制作一个最小的可重现代码。
I've tested it myself and yes, the problem still stays.我自己测试过,是的,问题仍然存在。 I get the exception "System.ArgumentOutOfRangeException " in the client side.
我在客户端收到异常“System.ArgumentOutOfRangeException”。
Server code :服务器代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
//
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace BugServeurSocket1
{
public partial class Form1 : Form
{
private Socket MonServeur, MonClient;
int bufferSize = 256;
private byte[] MonBuffer;
int portServeur = 8000;
string tAdversaire = "1";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MonBuffer = new byte[bufferSize];
#region mise en place serveur
IPAddress IPServeur = CorrectAddress(Dns.GetHostName());
MonServeur = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
MonServeur.Bind(new IPEndPoint(IPServeur, portServeur));
MonServeur.Listen(10);
MonServeur.BeginAccept(new AsyncCallback(SurDemandeConnexion), MonServeur);
#endregion
}
//réseau
#region fct perso
#region verif adr ipv4
private IPAddress CorrectAddress(string nPC)
{
IPAddress ipReponse = null;
if (nPC.Length > 0)
{
IPAddress[] IPserveur = Dns.GetHostEntry(nPC).AddressList;
for (int i = 0; i < IPserveur.Length; i++)
{
Ping pingServeur = new Ping();
//envoyer ping
PingReply pingResponse = pingServeur.Send(IPserveur[i]);
if (pingResponse.Status == IPStatus.Success)
if (IPserveur[i].AddressFamily == AddressFamily.InterNetwork)
{
ipReponse = IPserveur[i];
break;
}
}//for
}
return ipReponse;
}
#endregion
#region reception connexion client
public void SurDemandeConnexion(IAsyncResult iar)
{
Socket tmp = (Socket)iar.AsyncState;
MonServeur.BeginAccept(new AsyncCallback(SurDemandeConnexion), MonServeur);//accepter nouvelles connexions
MonClient = tmp.EndAccept(iar);
//MonBuffer = new byte[256];//test
MonBuffer = Encoding.Unicode.GetBytes("Connexion acceptée");
MonClient.Send(MonBuffer, 0, MonBuffer.Length, SocketFlags.None);
//ver7
InitializeReceive(MonClient);
}
#endregion
public void InitializeReceive(Socket soc)
{
MonBuffer = new byte[256];//empty buffer//test
soc.BeginReceive(MonBuffer, 0, MonBuffer.Length,
SocketFlags.None, new AsyncCallback(ReceiveMsg), soc);
}
public void ReceiveMsg(IAsyncResult iar)
{
Socket tmp = (Socket)iar.AsyncState;
int received = tmp.EndReceive(iar);
if (received > 0)
{
string msg = Encoding.Unicode.GetString(MonBuffer, 0, received);
string[] msgSplit = msg.Split(':');
//pseudo
string msgKey = msgSplit[0];
#region recherche adversaire
if (msgKey == "JEU_CHERCHER_ADVERSAIRE")
{
MonBuffer = Encoding.Unicode.GetBytes("TESTJEU_CHERCHER_ADVERSAIRE:" + tAdversaire + ":"
+ tAdversaire + "=adversaire_RECHERCHE;joueur_RECHERCHANT");
MonClient.Send(MonBuffer, 0, MonBuffer.Length, SocketFlags.None);
}
#endregion
//next msg
InitializeReceive(tmp);
}
}
#endregion
}
}
Client code:客户端代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
//
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
namespace BugClientSocket1
{
public partial class Form1 : Form
{
private Socket MonClient;
//buffer
int bufferSize = 256;
private byte[] MonBuffer;
int portServeur = 8000;
string pseudoID = "1:";
string tAdversaire = "1";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
tPseudo.Text = pseudoID;
MonBuffer = new byte[bufferSize];
}
private IPAddress CorrectAddress(string nPC)
{
IPAddress ipReponse = null;
try
{
if (nPC.Length > 0)
{
IPAddress[] IPserveur = Dns.GetHostEntry(nPC).AddressList;
for (int i = 0; i < IPserveur.Length; i++)
{
Ping pingServeur = new Ping();
PingReply pingResponse = pingServeur.Send(IPserveur[i]);
if (pingResponse.Status == IPStatus.Success)
if (IPserveur[i].AddressFamily == AddressFamily.InterNetwork)
{
ipReponse = IPserveur[i];
break;
}
}//for
}
return ipReponse;
}
catch (SocketException e)
{
return null;
}
}
private void BConnecter_Click(object sender, EventArgs e)
{
MonClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
MonClient.Blocking = false;
//tserveur.txt -> replace with your PC name
IPAddress IPserveur = CorrectAddress(tServeur.Text);
if (IPserveur != null)
MonClient.BeginConnect(new IPEndPoint(IPserveur, portServeur), new AsyncCallback(OnConnection), MonClient);
}
#region Se connecter au serveur
public void OnConnection(IAsyncResult iar)
{
Socket tmp = (Socket)iar.AsyncState;
if (tmp.Connected)
{
byte[] msg = Encoding.Unicode.GetBytes("PSEUDO:" + tPseudo.Text);
//send pseudo
MonClient.Send(msg, 0, msg.Length, SocketFlags.None);
//next msg
InitializeReceive(tmp);
}
else
{
MessageBox.Show("Serveur inaccessible");
}
}
#endregion
#region Debut reception msg + suite
//cfr beginaccept-> beginreceive ici
public void InitializeReceive(Socket soc)
{
MonBuffer = new byte[bufferSize];
soc.BeginReceive(MonBuffer, 0, MonBuffer.Length,
SocketFlags.None, new AsyncCallback(ReceiveMsg), soc);
}
public void ReceiveMsg(IAsyncResult iar)
{
Socket tmp = (Socket)iar.AsyncState;
int received = tmp.EndReceive(iar);
if (received > 0)
{
string msg = Encoding.Unicode.GetString(MonBuffer, 0, received);
//next msg
InitializeReceive(tmp);
}
}
#endregion
private void BChercher_Click(object sender, EventArgs e)
{
if (MonClient != null && tPseudoAdversaire.Text != "")
{
//MonBuffer = new byte[bufferSize];
MonBuffer = Encoding.Unicode.GetBytes("JEU_CHERCHER_ADVERSAIRE:" + tAdversaire + ":"
+ pseudoID + "=adversaire_RECHERCHE;joueur_RECHERCHANT");
//send pseudo
MonClient.Send(MonBuffer, 0, MonBuffer.Length, SocketFlags.None);
}
}
}
}
I did let text on purpose (such as JEU_CHERCHER...), to get the exact same problem.我确实故意让文本(例如 JEU_CHERCHER ...)得到完全相同的问题。
My application is a winform in visual studio 2019我的应用程序是Visual Studio 2019 中的winform
To reproduce the bug, here the steps:要重现该错误,请执行以下步骤:
If you don't understand something (because i didn't translate all in english), please tell me.如果您有什么不明白的地方(因为我没有全部翻译成英文),请告诉我。 Thank you
谢谢
To sum it up, the solution is:总结一下,解决方法是:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.