我有一个使用Asynchronous Socket的客户端/服务器应用程序。我有一个从服务器端向客户端发送数据的方法,客户端有一个方法来处理这些数据并控制客户端的表单控制。
由于使用Async套接字,我需要使用Control.Invoke
方法来访问主线程。但是我遇到了一个问题 - 在我使用Control.Invoke
后,它开始向服务器端发送数据问题。它进入socketClient.Send(byteArray);但不是将数据发送到服务器。如果我不使用Invoke.Method我无法控制客户端表单控件:(
我必须做什么?
好的我发现了我的问题,但它不是关于Control.Invoke它的套接字数据传输问题。但我无法解决它。当我使用repeadetly socketClient.Send()方法时,只有第一个socketclient.Send()正在工作其他没有。这是我的代码;
//当客户端连接时,此方法正在运行。
void baglantiSaglandi(IAsyncResult sonuc){
try
{
Aday gelenAday = new Aday();
bagliAdayListesi.Add(gelenAday);
gelenAday.adaySoket = serverSocket.EndAccept(sonuc);
TamponTemizle();
// Client'in gönderdiği veriyi kabul edip, boyutunu gelendataBoyutu isimli değişkene atadık.
int gelendataBoyutu = gelenAday.adaySoket.Receive(tampon);
// Client'in ip adresini ipadresi property imize ekledik.
gelenAday.ipAdresi = Mesaj(StringeDonustur(tampon, gelendataBoyutu));
lstKullanicilar.Items.Add(gelenAday.ipAdresi);
grpYonetim.Enabled = true;
lblUyari.Visible = false;
serverSocket.BeginAccept(new AsyncCallback(baglantiSaglandi), null);
TamponTemizle();
gelenAday.adaySoket.BeginReceive(tampon, 0, tampon.Length, SocketFlags.None, new AsyncCallback(mesajGeldi), gelenAday);
}
catch (SocketException ex)
{
MessageBox.Show(ex.Message);
}
}
//当客户端向服务器发送消息时,此代码块正在运行。
void mesajGeldi(IAsyncResult sonuc){
Aday stateAday = sonuc.AsyncState as Aday;
try
{
int gelenDataBoyutu = stateAday.adaySoket.EndReceive(sonuc);
MesajKontrol(StringeDonustur(tampon, gelenDataBoyutu), stateAday.ipAdresi);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.ConnectionReset)
{
foreach (Aday cikanAday in bagliAdayListesi)
{
if (cikanAday.ipAdresi == stateAday.ipAdresi)
{
cikanAday.adaySoket.Close();
bagliAdayListesi.Remove(cikanAday);
// lstKullanicilar.Items.Remove(cikanAday.ipAdresi);
if (lstKullanicilar.Items.Count <= 0)
{
grpYonetim.Enabled = false;
lblUyari.Visible = true;
}
break;
}
}
}
}
}
//此方法正在处理客户的消息
void MesajKontrol(string mesaj, string aday)
{
if (mesaj.Length < 1)
return;
switch (mesaj.Substring(0, 3))
{
case "/s/":
string[] yanlisDogru = Mesaj(mesaj).Split(',');
foreach (Aday cikanAday in bagliAdayListesi)
{
if (cikanAday.ipAdresi == aday)
{
lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add(yanlisDogru[1]);
lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add(yanlisDogru[0]);
}
}
break;
case "/q/":
foreach (Aday cikanAday in bagliAdayListesi)
{
if (cikanAday.ipAdresi == aday)
{
cikanAday.adaySoket.Close();
bagliAdayListesi.Remove(cikanAday);
//lstKullanicilar.Items.Remove(cikanAday.ipAdresi);
if (lstKullanicilar.Items.Count <= 0)
{
grpYonetim.Enabled = false;
lblUyari.Visible = true;
}
break;
}
}
break;
case "/b/":
foreach (Aday cikanAday in bagliAdayListesi)
{
if (cikanAday.ipAdresi == aday)
{
lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add(Mesaj(mesaj));
lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add("0");
lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add("0");
}
}
break;
default:
break;
}
}
//这个代码块正在从客户端开始工作,问题从这里开始有2个Send方法正常工作,但只有第一个在服务器上执行。
private void btnYazdir_Click(object sender, EventArgs e)
{
clientSocket.Send(ByteArrayeDonustur("/s/" + yanlis.ToString() + "," + dogru.ToString()));
clientSocket.Send(ByteArrayeDonustur("/b/" + txtAdSoyad.Text));
}
答案 0 :(得分:2)
你没有使用异步套接字,如果那时你要么调用Socket.BeginSend或Socket.SendAsync。调用Socket.Send
不是异步的,事实上它是非常同步!
我看不出调用方法与你无法发送数据有什么关系...你当前正在描述套接字数据传输问题,但你给我们的代码示例显示了你在主线程上调用invoke,它启动new Thread
并以某种方式导致套接字转到AWOL!
请提供符合sscce标准的代码示例,我们可以用它来重现您的问题(至少)或提供一些更相关的代码:
这是我的版本......我首先制作方法BeginReceive
。它设置套接字接收并在套接字上调用BeginReceive
方法:
private void BeginReceive()
{
if ( _clientState == EClientState.Receiving)
{
if (_asyncTask.BytesReceived != 0 && _asyncTask.TotalBytesReceived <= _maxPageSize)
{
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.SetBuffer(_asyncTask.ReceiveBuffer, 0, _asyncTask.ReceiveBuffer.Length);
e.Completed += new EventHandler<SocketAsyncEventArgs>(ReceiveCallback);
e.UserToken = _asyncTask.Host;
bool comletedAsync = false;
try
{
comletedAsync = _socket.ReceiveAsync(e);
}
catch (SocketException se)
{
Console.WriteLine("Error receiving data from: " + _asyncTask.Host);
Console.WriteLine("SocketException: {0} Error Code: {1}", se.Message, se.NativeErrorCode);
ChangeState(EClientState.Failed);
}
if (!comletedAsync)
{
// The call completed synchronously so invoke the callback ourselves
ReceiveCallback(this, e);
}
}
else
{
//Console.WriteLine("Num bytes received: " + _asyncTask.TotalBytesReceived);
ChangeState(EClientState.ReceiveDone);
}
}
}
这是接收回调(请注意,它再次调用BeginReceive
):
private void ReceiveCallback(object sender, SocketAsyncEventArgs args)
{
lock (_sync) // re-entrant lock
{
// Fast fail: should not be receiving data if the client
// is not in a receiving state.
if (_clientState == EClientState.Receiving)
{
String host = (String)args.UserToken;
if (_asyncTask.Host == host && args.SocketError == SocketError.Success)
{
try
{
Encoding encoding = Encoding.ASCII;
_asyncTask.BytesReceived = args.BytesTransferred;
_asyncTask.TotalBytesReceived += _asyncTask.BytesReceived;
_asyncTask.DocSource += encoding.GetString(_asyncTask.ReceiveBuffer, 0, _asyncTask.BytesReceived);
BeginReceive(); // <---- THIS IS WHAT YOU'RE MISSING
}
catch (SocketException e)
{
Console.WriteLine("Error receiving data from: " + host);
Console.WriteLine("SocketException: {0} Error Code: {1}", e.Message, e.NativeErrorCode);
ChangeState(EClientState.Failed);
}
}
else if (_asyncTask.Host != host)
{
Console.WriteLine("Warning: received a callback for {0}, but the client is currently working on {1}.",
host, _asyncTask.Host);
}
else
{
Console.WriteLine("Socket Error: {0} when receiving from {1}",
args.SocketError,
_asyncTask.Host);
ChangeState(EClientState.Failed);
}
}
}
}
换句话说,你称之为:
gelenAday.adaySoket.BeginReceive(tampon, 0, tampon.Length, SocketFlags.None, new AsyncCallback(mesajGeldi), gelenAday);
在mesajGeldi
中,您应该调用调用上述方法的函数。您应该在仅负责调用begin / receive的方法中隔离该调用(如我的示例所示),并且它不会对建立套接字连接执行任何操作。