Reputation: 41
So I have two laptops connected to the same wifi network with one running a very simple server and the other a very simple client connecting to it. When I run both the server and the client on one laptop they connect without a problem, but when running one on each laptop the client cannot connect to the server.
The code for the server is this:
using System;
using System.Net;
using System.Net.Sockets;
namespace Utils
{
/// <summary>
/// A base server which handles listening for client connections and has simple API to communicate back and forth
/// </summary>
public class BaseServer
{
#region Properties and Fields
/// <summary>
/// The listener we can use to detect incoming connections from clients to the server
/// </summary>
private TcpListener Listener { get; set; }
/// <summary>
/// Our interface to the single client we are supporting for now
/// </summary>
public Comms ClientComms { get; private set; }
/// <summary>
/// Determines whether we have clients connected
/// </summary>
public bool Connections { get; private set; }
#endregion
public BaseServer()
{
Listener = new TcpListener(IPAddress.Any, 1490);
Listener.Start();
ListenForNewClient();
}
/// <summary>
/// Starts an asynchronous check for new connections
/// </summary>
private void ListenForNewClient()
{
Listener.BeginAcceptTcpClient(AcceptClient, null);
}
/// <summary>
/// Callback for when a new client connects to the server
/// </summary>
/// <param name="asyncResult"></param>
protected virtual void AcceptClient(IAsyncResult asyncResult)
{
ClientComms = new Comms(Listener.EndAcceptTcpClient(asyncResult));
ClientComms.OnDataReceived += ProcessMessage;
ListenForNewClient();
}
#region Message Callbacks
/// <summary>
/// A function which is called when the Client sends a message to the server.
/// Override to perform custom message handling
/// </summary>
/// <param name="data"></param>
protected virtual void ProcessMessage(byte[] data) { }
#endregion
}
}
And the code for the client is this:
using System;
using System.Net.Sockets;
namespace Utils
{
/// <summary>
/// A base client class which connects and communicates with a remote server
/// </summary>
public class BaseClient
{
#region Properties and Fields
/// <summary>
/// The interface to the server
/// </summary>
public Comms ServerComms { get; private set; }
#endregion
public BaseClient(string ipAddress, int portNumber = 1490)
{
// Attempt to connect
try
{
ServerComms = new Comms(new TcpClient(ipAddress, portNumber));
ServerComms.OnDataReceived += OnMessageReceived;
ServerComms.OnDisconnect += OnServerDisconnect;
}
catch (Exception e)
{
Console.WriteLine("Connection failed");
}
}
#region Callbacks
/// <summary>
/// A function which is called when this client receives a message.
/// Override to perform behaviour when custom messages arrive.
/// </summary>
/// <param name="data"></param>
protected virtual void OnMessageReceived(byte[] data) { }
/// <summary>
/// A function called when this client can no longer communicate to the server it is connected to
/// </summary>
protected virtual void OnServerDisconnect() { }
#endregion
}
}
The server is started from the main loop like this:
using System;
namespace BuildServer
{
class Program
{
static void Main(string[] args)
{
BaseServer server = new BaseServer();
while (true)
{
}
}
}
}
and the Client is started like this:
using System;
using Utils;
namespace BuildServerClient
{
class Program
{
static void Main(string[] args)
{
BaseClient client = new BaseClient();
while (true)
{
Console.WriteLine("Ready");
string message = Console.ReadLine();
client.ServerComms.Send(message);
}
}
}
}
One final class is a Comms class which is really a wrapper around the TCPClient and not really used currently, but I am adding it for the same of completeness.
using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using static Utils.Delegates;
namespace Utils
{
/// <summary>
/// An interface to a client.
/// Hides the nuts and bolts and provides a public interface of just data input and output from a data sender/receiver.
/// </summary>
public class Comms
{
#region Properties and Fields
private TcpClient Client { get; set; }
private MemoryStream ReadStream { get; set; }
private MemoryStream WriteStream { get; set; }
private BinaryReader Reader { get; set; }
private BinaryWriter Writer { get; set; }
/// <summary>
/// Useful buffer for reading packeted messages from the server
/// </summary>
private byte[] ReadBuffer { get; set; }
/// <summary>
/// An event that is fired when this Comms receives a message
/// </summary>
public event OnDataReceived OnDataReceived;
/// <summary>
/// An event that is fired when this Comms can no longer communicate with the client sending it messages
/// </summary>
public event OnDisconnect OnDisconnect;
#endregion
public Comms(TcpClient client)
{
Client = client;
ReadStream = new MemoryStream();
WriteStream = new MemoryStream();
Reader = new BinaryReader(ReadStream);
Writer = new BinaryWriter(WriteStream);
ReadBuffer = new byte[2048];
Client.NoDelay = true;
StartListening();
}
#region Data Sending Functions
/// <summary>
/// Convert a string to a byte array and then send to our client
/// </summary>
/// <param name="client"></param>
/// <param name="str"></param>
public void Send(string str)
{
SendByteArray(Encoding.UTF8.GetBytes(str));
}
/// <summary>
/// Send a byte array to our client
/// </summary>
/// <param name="client"></param>
/// <param name="bytes"></param>
protected void SendByteArray(byte[] bytes)
{
Writer.Write(bytes);
int bytesWritten = (int)WriteStream.Position;
byte[] result = new byte[bytesWritten];
WriteStream.Position = 0;
WriteStream.Read(result, 0, bytesWritten);
WriteStream.Position = 0;
Client.GetStream().BeginWrite(result, 0, result.Length, null, null);
Writer.Flush();
}
#endregion
#region Data Receiving Functions
/// <summary>
/// Start listening for messages from the server
/// </summary>
private void StartListening()
{
try
{
Client.GetStream().BeginRead(ReadBuffer, 0, 2048, StreamReceived, null);
}
catch
{
OnDisconnect?.Invoke();
}
}
/// <summary>
/// Callback which processes a message sent from the server
/// </summary>
/// <param name="ar"></param>
private void StreamReceived(IAsyncResult ar)
{
int bytesRead = 0;
try
{
lock (Client.GetStream())
{
bytesRead = Client.GetStream().EndRead(ar);
}
}
catch { }
//Create the byte array with the number of bytes read
byte[] data = new byte[bytesRead];
//Populate the array
for (int i = 0; i < bytesRead; i++)
{
data[i] = ReadBuffer[i];
}
OnDataReceived?.Invoke(data);
//Listen for new data
StartListening();
}
#endregion
}
}
The IP Addresses and Port numbers are correct and since it works when running on the same machine, I was thinking it might be a firewall issue or something? Does anyone have any ideas as to what might be causing this problem?
Upvotes: 0
Views: 2467
Reputation: 41
David's answer was correct. I previously tried it with just the firewall disabled for private networks. However, I disabled the firewall for guest and public networks and it worked a treat.
The method of testing proposed by codenoir was also very effective at ruling out my client. I suspected it was something to do with the firewall, but once you rule out the impossible...
Thanks to both
Upvotes: 0
Reputation: 4724
Make sure the firewall (Windows Firewall, or whatever's there) is turned off on the server machine, or there's a firewall exception for your port number.
Upvotes: 3