【发布时间】:2016-09-30 13:45:13
【问题描述】:
我在我的 C# 应用程序中同时使用 BeginSend 和 BeginReceive。它是一个客户端监听器,只会接收来自服务器的数据。我正在使用 BeginReceive 来获取数据。
但我发现仅接收并不足以保持连接的活跃和稳定。因此,我决定让我的应用程序始终使用 BeginSend ping 服务器以保持连接处于活动状态。
下面是我的代码:
private void timer1_Tick(object sender, EventArgs e)
{
DataProcess();
}
public Socket _serverSocket = null;
private byte[] _recieveBuffer = new byte[128];
byte[] AllBytes;
void DataProcess()
{
//TimeSpan ts;
try
{
//Thread.Sleep(100);
if (_serverSocket == null || sockState == MySocketState.Disconnected)
{
Console.WriteLine("Trying to connect...");
SetupServer();
}
else
{
AllBytes = ASCIIEncoding.ASCII.GetBytes(COM_DeviceIsOnline);
_serverSocket.BeginSend(AllBytes, 0, AllBytes.Length, SocketFlags.None, new AsyncCallback(SendCallback), null);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void SetupServer()
{
try
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Connect(_sIP, Int32.Parse(_sPort));
}
catch (SocketException ex)
{
Console.WriteLine(ex.Message);
}
if (_serverSocket.Connected)
{
sockState = MySocketState.Connected;
browser.ExecuteScriptAsync("svrConnect();");
Console.WriteLine("Server connected...");
_serverSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}
}
void SendCallback(IAsyncResult ar)
{
try
{
int bytesSent = _serverSocket.EndSend(ar);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_serverSocket == null)
_serverSocket = (Socket)AR.AsyncState;
//Check how much bytes are recieved and call EndRecieve to finalize handshake
int recieved = _serverSocket.EndReceive(AR);
if (recieved <= 0)
{
CloseSocket();
return;
}
//Copy the recieved data into new buffer , to avoid null bytes
byte[] recData = new byte[recieved];
Buffer.BlockCopy(_recieveBuffer, 0, recData, 0, recieved);
string strData = ASCIIEncoding.ASCII.GetString(recData);
Console.WriteLine(strData);
//Process data here the way you want , all your bytes will be stored in recData
int nSOHPos = -1;
int nSTXPos = -1;
int nETXPos = -1;
int nEOTPos = -1;
nSOHPos = Array.IndexOf(recData, SOH);
nSTXPos = Array.IndexOf(recData, STX);
nETXPos = Array.IndexOf(recData, ETX);
nEOTPos = Array.IndexOf(recData, EOT);
if ((nSOHPos == -1) || (nSTXPos == -1) || (nETXPos == -1) || (nEOTPos == -1))
{
CloseSocket();
return;
}
if (nSOHPos > nSTXPos ||
nSTXPos > nETXPos ||
nETXPos > nEOTPos)
{
CloseSocket();
return;
}
if ((nETXPos - nSTXPos) < 6)
{
CloseSocket();
return;
}
string _sCommand = ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 6, 2);
if ((_sCommand == "CN") || (_sCommand == "CL") || (_sCommand == "CR"))
{
nDept = int.Parse(ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 12, 2));
if (nDept != dept_id) return;
nCntr = int.Parse(ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 14, 2));
nServ = int.Parse(ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 16, 2));
sQnum = ASCIIEncoding.ASCII.GetString(recData, nSTXPos + 8, 4);
string[] sSplit = strData.Split('^');
string sCusName = sSplit[1];
//if (_sCommand == "CR") sCusName = " ";
Console.WriteLine("Dept ID = " + nDept);
Console.WriteLine("Cntr ID = " + nCntr);
Console.WriteLine("Serv ID = " + nServ);
Console.WriteLine("Queue No = " + sQnum);
Console.WriteLine("Cus Name = " + sCusName);
var script = string.Format("nextCall(\'{0}\', {1}, {2});", sQnum, nCntr, nServ);
browser.ExecuteScriptAsync(script);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
CloseSocket();
}
finally
{
try
{
//Start receiving again
if (_serverSocket != null)
_serverSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
//theDevSock.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, ReceiveCallback, theDevSock);
}
catch (Exception ex2)
{ }
}
}
public void CloseSocket()
{
try
{
if (_serverSocket != null)
{
if (_serverSocket.Connected)
_serverSocket.Shutdown(SocketShutdown.Both);
_serverSocket.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
_serverSocket = null;
sockState = MySocketState.Disconnected;
browser.ExecuteScriptAsync("svrDisconnect();");
}
我的应用程序开始连接到服务器。连接到服务器后,它将开始 ping 服务器。但我发现每次使用 BeginSend ping 服务器后,都会出现错误“线程 0x1ff0 已退出,代码为 259 (0x103)”。并且与服务器的连接将被断开,我的应用程序将重新尝试再次连接服务器。然后在连接成功后,再次ping服务器时,它再次断开连接。
我可以知道我的编码是否正确编写?我可以像这样使用 BeginSend 来 ping 服务器吗?
【问题讨论】:
-
要保持连接活跃,您可以使用
SetSocketOption方法,例如:socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true); -
我应该在哪里添加这行代码?可以推荐吗?
-
这真的取决于你的应用逻辑是怎样的,但一般的方法是在你连接之前设置套接字选项。
-
你是什么意思,“保持连接活跃”? TCP 可以永远保持没有数据的开放连接,除非线路上有其他东西破坏了它。一个更大的问题是您没有使用任何消息框架,这根本不适用于 TCP - TCP 是基于流的协议,而不是基于消息的协议;如果需要消息,则需要添加自己的消息协议。
-
@raidensan,我试着把它放进去,它有以下错误:在getsockopt或setsockopt调用中指定了未知、无效或不受支持的选项或级别第一次机会异常类型为'System.Net System.dll 中发生 .Sockets.SocketException'
标签: c# winforms visual-studio sockets server