I've made a small chat application using asynchronous sockets in C#.
The chat is made for multiple clients.
Here's the problem: When I opened the server on my Loopback IP (127.0.0.1), and opened a few clients on my computer, I successfully sent messages between them.
But when I opened the server on my computer (127.0.0.1), and opened a client on another computer, the communication failed. When I tried to connect to the server from another computer, the client crashed (because it couldn't connect).
The codes:
Server:
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);
}
}
}
Client:
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 = "";
}
}
}
Again, when I opened 2 clients and a server on my computer, the clients successfully communicated through the server.
But when I opened the server on my computer, I couldn't connect to it through another computers with port 1234 (which the server listens to).
I haven't forwarded port 1234, if that matters (I don't think it should matter since the server is listening to that port).
Why is this? And how can I fix it?