C# 客户端 - 服务器套接字断开处理
Posted
技术标签:
【中文标题】C# 客户端 - 服务器套接字断开处理【英文标题】:C# Client - Server Socket Disconnect Handling 【发布时间】:2016-01-15 21:09:48 【问题描述】:我正在编写我的论文时有一个客户端 - 服务器代码。 而且我可以产生一个连接并发送数据,但是一旦客户端断开连接并尝试重新连接,一切都会横向运行,我似乎无法弄清楚为什么。抛出了太多异常,我只是不知道从哪里开始捕获它们。 什么做错或不做不允许下界客户端或服务器正确处理断开连接?!
这是我的服务器端代码:
using System;
using System.Net;
using System.Net.Sockets;
namespace Server.Networking
public class ServerSocket
private Socket _socket;
Byte[] _buffer = new byte[61144];
public ServerSocket()
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public void Bind(int port)
_socket.Bind(new IPEndPoint(IPAddress.Any, port));
public void Listener(int backlog)
_socket.Listen(backlog);
public void Accept()
_socket.BeginAccept(AcceptedCallback, null);
private void AcceptedCallback(IAsyncResult result)
try
Socket clientSocket = _socket.EndAccept(result);
if (clientSocket.Connected)
Console.WriteLine("Client has connected!");
_buffer = new byte[61144];
clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
Accept();
else
Console.WriteLine("Client hasn't connected!");
return;
catch(SocketException ex)
Console.WriteLine(ex.Message);
close(clientSocket);
private void ReceivedCallback(IAsyncResult result)
try
Socket clientSocket = result.AsyncState as Socket;
SocketError SE;
int bufferSize = clientSocket.EndReceive(result, out SE);
if (bufferSize > 0)
if (SE == SocketError.Success)
byte[] packet = new byte[bufferSize];
Array.Copy(_buffer, packet, packet.Length);
Console.WriteLine("Handling packet from IP:" + clientSocket.RemoteEndPoint.ToString());
//Handle packet stuff here.
PacketHandler.Handle(packet, clientSocket);
_buffer = new byte[61144];
clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
else
close(clientSocket);
else
Console.WriteLine("Probably received bad data.");
close(clientSocket);
catch (SocketException ex)
Console.WriteLine(ex.Message);
close(clientSocket);
public void close(Socket sock)
Console.WriteLine("Closing socket for IP:" + sock.RemoteEndPoint.ToString() + " and releasing resources.");
sock.Dispose();
sock.Close();
这是我的客户端代码:
using System;
using System.Net;
using System.Linq;
using System.Net.Sockets;
using Client.Networking.Packets;
using System.Net.NetworkInformation;
using Client.Networking.Packets.Request;
namespace Client.Networking
public class ClientSocket
private Socket _socket;
private byte[] _buffer;
public delegate void RaiseConnect(object source, TextArgs e);
public static event EventHandler Disconnected;
private static void RaiseDisconnect()
EventHandler handler = Disconnected;
if(handler !=null)
handler(null, EventArgs.Empty);
public ClientSocket()
udpbroadcast.Connect += new RaiseConnect(OnConnectRaise);
public string machineIP()
return Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString();
private void OnConnectRaise(object sender, TextArgs e)
CheckRegisteredRequest computer_name = new CheckRegisteredRequest(Environment.MachineName.ToString() + "," + machineIP());
Connect(e.Message, 6556);
Send(computer_name.Data);
public void Connect(string ipAddress, int port)
string ip = ipAddress;
int porT = port;
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result =_socket.BeginConnect(new IPEndPoint(IPAddress.Parse(ip), port), ConnectCallback, null);
bool success = result.AsyncWaitHandle.WaitOne(5000, true);
if(!success)
_socket.Close();
Console.WriteLine("Failed to connect to server. Trying again.");
Connect(ip, port);
private void ConnectCallback(IAsyncResult result)
try
if (_socket.Connected)
Console.WriteLine("Connected to the server!");
_buffer = new byte[61144];
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);
else
Console.WriteLine("Could not connect.");
Close(_socket);
catch(SocketException ex)
Console.WriteLine("ClientSocket ConnectCallback - "+ex.Message);
Close(_socket);
private void ReceivedCallback(IAsyncResult result)
try
SocketError SE;
int buflength = _socket.EndReceive(result, out SE);
if (buflength > 0)
if(SE == SocketError.Success)
byte[] packet = new byte[buflength];
Array.Copy(_buffer, packet, packet.Length);
//Handle the Package
PacketHandler.Handle(packet, _socket);
_buffer = new byte[61144];
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);
else
Close(_socket);
else
Close(_socket);
catch (Exception ex)
Console.WriteLine("ClientSocket ReceivedCallback - " + ex.Message);
Close(_socket);
public void Send(byte[] data)
byte[] send = new byte[data.Length];
send = data;
if( _socket.Connected)
_socket.Send(data);
else
Console.WriteLine("Not connected yet!");
Close(_socket);
public bool connectionStatus()
return _socket.Connected;
public static void Close(Socket sock)
Console.WriteLine("Closing the socket and releasing resources.");
sock.Dispose();
sock.Close();
RaiseDisconnect();
【问题讨论】:
在此处查看我的答案(每次客户端连接时都需要再次调用BeginAccept
以接受新连接;我建议将其线程化):***.com/questions/30688760/…
【参考方案1】:
我能想到两件事。 Socket 上的文档建议在 Close() 之前先调用 Shutdown()。
此外,您不能重用套接字对象。因此,请确保在尝试新连接之前使用新的 Socket 对象,或者通过 _socket = new Socket(),或者使用全新的 ServerSocket/ClientSocket。
【讨论】:
【参考方案2】:我设法让它与以下代码一起工作。在服务器代码中,我通过 AcceptedCallback 以下列方式启动 BeginReceive:
clientSocket.BeginReceive(new byte[] 0, 0, 0, 0, ReceivedCallback, clientSocket);
然后在 ReceivedCallback 中,我会像这样以不同的方式开始接收:
clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
虽然受到异常的困扰,但我似乎跳过了检查我在初始连接中收到的内容。
在客户端代码中,在 ConnectCallback 方法中,我确实开始以相反的方式接收:
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);
在 ReceivedCallback 方法中,我反向执行了 BeginReceive:
_socket.BeginReceive(new byte[] 0 , 0, 0, 0, ReceivedCallback, null);
经过三个小时的调试,这在某种程度上对我来说是有意义的。 服务器每次接受连接时都会产生一个新的套接字对象,以避免线程化。所以在Server端的AcceptedCallback方法,初始的_socket.BeginReceive应该通过一个空字节数组调用ReceivedCallback方法才触发它。然后在 ReceivedCallback 中,您使用一个自定义为套接字接收到的长度的数组来执行 BeginReceive。而在客户端,则相反。
这是我的服务器端代码:
private Socket _socket;
Byte[] _buffer = new byte[61144];
public ServerSocket()
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public void Bind(int port)
_socket.Bind(new IPEndPoint(IPAddress.Any, port));
public void Listener(int backlog)
_socket.Listen(backlog);
public void Accept()
_socket.BeginAccept(AcceptedCallback, null);
private void AcceptedCallback(IAsyncResult result)
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
Console.WriteLine("We accepted a connection.");
clientSocket = _socket.EndAccept(result);
if (clientSocket.Connected)
Console.WriteLine("Client has connected!");
_buffer = new byte[61144];
//clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
clientSocket.BeginReceive(new byte[] 0, 0, 0, 0, ReceivedCallback, clientSocket);
Accept();
else
Console.WriteLine("Client hasn't connected!");
Accept();
catch (Exception ex)
Console.WriteLine("Socket was probably forcefully closed." + ex.Message);
Console.WriteLine("Continue accepting other connections.");
clientSocket.Close();
Accept();
private void ReceivedCallback(IAsyncResult result)
Socket clientSocket = result.AsyncState as Socket;
SocketError ER;
try
int bufferSize = clientSocket.EndReceive(result, out ER);
if (ER == SocketError.Success)
byte[] packet = new byte[bufferSize];
Array.Copy(_buffer, packet, packet.Length);
Console.WriteLine("Handling packet from IP:" + clientSocket.RemoteEndPoint.ToString());
//Handle packet stuff here.
PacketHandler.Handle(packet, clientSocket);
_buffer = new byte[61144];
clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
//clientSocket.BeginReceive(new byte[] 0 , 0, 0, 0, ReceivedCallback, clientSocket);
else
Console.WriteLine("No bytes received, we're closing the connection.");
clientSocket.Close();
catch(SocketException ex)
Console.WriteLine("We caught a socket exception:" + ex.Message);
clientSocket.Close();
这是我的客户端代码:
private Socket _socket;
private CheckRegisteredRequest computer_name;
private bool isClosed;
private byte[] _buffer;
public delegate void RaiseConnect(object source, TextArgs e);
public static event EventHandler Disconnected;
private static void RaiseDisconnect()
EventHandler handler = Disconnected;
if (handler != null)
handler(null, EventArgs.Empty);
public ClientSocket()
isClosed = true;
udpbroadcast.Connect += new RaiseConnect(OnConnectRaise);
computer_name = new CheckRegisteredRequest(Environment.MachineName.ToString() + "," + machineIP());
private void OnConnectRaise(object sender, TextArgs e)
if(!isClosed)
_socket.Close();
Connect(e.Message, 6556);
else
Connect(e.Message, 6556);
public void Connect(string ipAddress, int port)
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.BeginConnect(new IPEndPoint(IPAddress.Parse(ipAddress), port), ConnectCallback, null);
isClosed = false;
/*IAsyncResult result =
bool success = result.AsyncWaitHandle.WaitOne(5000, true);
if (!success)
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
Console.WriteLine("Failed to connect to server. Trying again.");
RaiseDisconnect();
*/
private void ConnectCallback(IAsyncResult result)
try
if(_socket.Connected)
_socket.EndConnect(result);
Console.WriteLine("We initiated a connection to the server.");
Console.WriteLine("Connected to the server!");
Send(computer_name.Data);
_buffer = new byte[61144];
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);
else
Console.WriteLine("Could not connect.");
if(!isClosed)
_socket.Close();
isClosed = true;
RaiseDisconnect();
else
isClosed = true;
RaiseDisconnect();
catch (SocketException ex)
Console.WriteLine("ConnectCallback Exception Caught.");
Console.WriteLine("Shutting down and closing socket for reusal.");
if (!isClosed)
_socket.Close();
isClosed = true;
RaiseDisconnect();
else
isClosed = true;
RaiseDisconnect();
private void ReceivedCallback(IAsyncResult result)
try
SocketError SE;
int buflength = _socket.EndReceive(result, out SE);
if (SE == SocketError.Success)
byte[] packet = new byte[buflength];
Array.Copy(_buffer, packet, packet.Length);
//Handle the Package
PacketHandler.Handle(packet, _socket);
_buffer = new byte[61144];
//_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, null);
_socket.BeginReceive(new byte[] 0 , 0, 0, 0, ReceivedCallback, null);
else
Console.WriteLine("No bytes received, we're closing the connection.");
if (!isClosed)
_socket.Close();
isClosed = true;
RaiseDisconnect();
else
isClosed = true;
RaiseDisconnect();
catch (Exception ex)
Console.WriteLine("ReceivedCallback Exception Caught.");
Console.WriteLine("Shutting down and closing socket for reusal.");
if (!isClosed)
_socket.Close();
isClosed = true;
RaiseDisconnect();
else
isClosed = true;
RaiseDisconnect();
public void Send(byte[] data)
byte[] send = new byte[data.Length];
send = data;
if (_socket.Connected)
_socket.Send(data);
else
Console.WriteLine("We're not connected yet!");
if (!isClosed)
_socket.Close();
isClosed = true;
RaiseDisconnect();
else
isClosed = true;
RaiseDisconnect();
public bool connectionStatus()
return _socket.Connected;
public string machineIP()
return Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString();
【讨论】:
以上是关于C# 客户端 - 服务器套接字断开处理的主要内容,如果未能解决你的问题,请参考以下文章
如何在socket.io中的断开事件上获取断开连接的客户端的套接字ID