我在C#中使用异步套接字创建了一个小型聊天应用程序。
为多个客户进行聊天。
问题在于:当我在Loopback IP(127.0.0.1)上打开服务器,并在我的计算机上打开了几个客户端时,我成功地在它们之间发送了消息。
但是当我在计算机上打开服务器(127.0.0.1)并在另一台计算机上打开客户端时,通信失败。当我尝试从另一台计算机连接到服务器时,客户端崩溃了(因为它无法连接)。
代码:
服务器
namespace ServerForm
{
public partial class Form1 : Form
{
private Socket _serverSocket;
private readonly List<Socket> _clientSockets = new List<Socket>();
private const int _BUFFER_SIZE = 2048;
private const int _PORT = 513;
private readonly byte[] _buffer = new byte[_BUFFER_SIZE];
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
SetupServer();
}
private void SetupServer()
{
//Console.WriteLine("Setting up server...");
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(new IPEndPoint(0, 1234));
_serverSocket.Listen(5);
_serverSocket.BeginAccept(AcceptCallback, null);
//Console.WriteLine("Server setup complete");
}
private void CloseAllSockets()
{
foreach (Socket socket in _clientSockets)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
_serverSocket.Close();
}
private void AcceptCallback(IAsyncResult AR)
{
Socket socket;
try
{
socket = _serverSocket.EndAccept(AR);
}
catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
{
return;
}
_clientSockets.Add(socket);
socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
//Console.WriteLine("Client connected, waiting for request...");
_serverSocket.BeginAccept(AcceptCallback, null);
}
private void ReceiveCallback(IAsyncResult AR)
{
Socket current = (Socket)AR.AsyncState;
int received;
try
{
received = current.EndReceive(AR);
}
catch (SocketException)
{
//Console.WriteLine("Client forcefully disconnected");
current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
_clientSockets.Remove(current);
return;
}
byte[] recBuf = new byte[received];
Array.Copy(_buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);
//Console.WriteLine("Received Text: " + text);
if (text.ToLower() == "get time") // Client requested time
{
//Console.WriteLine("Text is a get time request");
byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
for (int i = 0; i < _clientSockets.Count; i++) _clientSockets[i].Send(Encoding.ASCII.GetBytes(text));
//Console.WriteLine("Time sent to client");
}
else if (text.ToLower() == "exit") // Client wants to exit gracefully
{
// Always Shutdown before closing
current.Shutdown(SocketShutdown.Both);
current.Close();
_clientSockets.Remove(current);
Console.WriteLine("Client disconnected");
return;
}
else
{
//Console.WriteLine("Text is an invalid request");
byte[] data = Encoding.ASCII.GetBytes("Invalid request");
for (int i = 0; i < _clientSockets.Count; i++) _clientSockets[i].Send(Encoding.ASCII.GetBytes(text));
//Console.WriteLine("Warning Sent");
}
current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
}
}
}
客户端:
namespace ChatForm
{
public partial class Form1 : Form
{
private readonly Socket _clientSocket = new Socket
(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private const int _PORT = 1234;
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void label1_Click(object sender, EventArgs e)
{
}
private void connect_Click(object sender, EventArgs e)
{
if (name.Text == "" || s_ip.Text == "") MessageBox.Show("Fields cannot be empty.");
else ConnectToServer();
}
private void ConnectToServer()
{
IPAddress connection = IPAddress.Parse(s_ip.Text);
IPAddress server = connection;
int attempts = 1;
while (!_clientSocket.Connected)
{
try
{
_clientSocket.Connect(connection, _PORT);
}
catch (SocketException) // it crashes if it reaches here
{
}
}
MessageBox.Show("Successfully connected to server");
RequestLoop();
}
private void RequestLoop()
{
Thread t1 = new Thread(ReceiveResponse);
t1.Start();
}
/// <summary>
/// Close socket and exit app
/// </summary>
private void Exit()
{
SendString("exit");
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Close();
Environment.Exit(0);
}
private void SendRequest()
{
string request = "[" + name.Text + "] " + text.Text + "\n";
SendString(request);
if (request.ToLower() == "exit")
{
Exit();
}
}
/// <summary>
/// Sends a string to the server with ASCII encoding
/// </summary>
private void SendString(string text)
{
byte[] buffer = Encoding.ASCII.GetBytes(text);
_clientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);
//MessageBox.Show("Sent");
}
private void ReceiveResponse()
{
while (true)
{
var buffer = new byte[2048];
int received = _clientSocket.Receive(buffer, SocketFlags.None);
if (received == 0) return;
var data = new byte[received];
Array.Copy(buffer, data, received);
string text = Encoding.ASCII.GetString(data);
display.AppendText(text);
if (text.Contains("MessageBox!"))
{
MessageBox.Show(text.Split('!')[1]);
}
}
}
private void button2_Click(object sender, EventArgs e)
{
SendRequest();
text.Text = "";
}
}
}
同样,当我在计算机上打开2个客户端和服务器时,客户端已成功通过服务器进行通信。
但是当我在计算机上打开服务器时,我无法通过另一台端口1234(服务器监听)的计算机连接到它。
我没有转发端口1234,如果这很重要(我认为这不重要,因为服务器正在侦听该端口)。
这是为什么?我该如何解决?
答案 0 :(得分:1)
我认为你可以绑定到IPAddress.Any,即0.0.0.0,意味着监听所有接口活动
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 1234));
_serverSocket.Listen(5);
答案 1 :(得分:0)
如果您希望其他计算机能够连接,您只能在环回接口(127.0.0.1)上监听。该接口没有路由。 让服务器监听所有接口(0.0.0.0)或一个真正的IP地址(例如192.168.1.6?)