我正在处理论文时,我现在有一个客户端 - 服务器代码。 我可以产生一个连接并发送数据,但是一旦客户端断开连接并尝试重新连接,一切都会横向移动,我似乎无法找出原因。抛出的异常太多了,我只是不知道从哪里开始捕捉它们。 做错了什么或者没有做到这一点是不允许nether客户端或服务器正确处理断开连接?!
这是我的ServerSide代码:
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();
}
}
}
答案 0 :(得分:1)
我能想到的两件事。 Socket上的文档建议在Close()之前先调用Shutdown()。
此外,您无法重用套接字对象。因此,在尝试新连接之前,请确保使用新的Socket对象,可以通过_socket = new Socket(),也可以使用全新的ServerSocket / ClientSocket。
答案 1 :(得分:0)
我设法让它使用以下代码。在服务器代码中,我通过以下方式启动BeginReceive witihn AcceptedCallback :
clientSocket.BeginReceive(new byte[] {0}, 0, 0, 0, ReceivedCallback, clientSocket);
然后在 ReceivedCallback 中,我会以不同的方式执行BeginReceive:
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);
经过三个小时的调试,这对我来说很有意义。 每次接受连接时,服务器都会生成一个新的套接字对象,以避免线程化。因此,在服务器端的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();
}