Socket client-server app for exchanging sine-wave points
up vote
4
down vote
favorite
I wanted to try C# network programming and wrote this simple client/server application. The idea is - many clients can connect to server and request some data. As an example they request a set of points on sine-wave (required number of points and time span is up to each user).
The server then calculates required points and sends them to each user.
As this is my first program of that kind (and because I frankensteined it from 2 different examples) I guess there are definitely errors/smell here and I would be really grateful to hear them.
First - server setup:
class Program
{
static void Main(string args)
{
IPHostEntry iph = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverAddress = iph.AddressList[1];
int server_Port = 1337;
int maxConnections = 10;
Listener listener = new Listener(serverAddress, server_Port); // Setup server
listener.StartListening(maxConnections); // Start server
Console.Read();
}
}
// Here we accept new connections
class Listener
{
//This is the socket that will listen to any incoming connections
public Socket _serverSocket { get; private set; }
public int Port { get; private set; }
public int maxConnections { get; private set; }
public IPAddress ipAddress { get; private set; }
public Listener(IPAddress ServerIp, int ServerPort)
{
ipAddress = ServerIp;
Port = ServerPort;
_serverSocket = new Socket(ServerIp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
// Here we start waiting for new client
public void StartListening(int MaxConnections)
{
maxConnections = MaxConnections;
try
{
Console.WriteLine("Server started at IP:" + ipAddress.ToString() + "; port:" + Port.ToString() + ";n");
_serverSocket.Bind(new IPEndPoint(ipAddress, Port)); // Setup server at selected endpoint
_serverSocket.Listen(MaxConnections); // Limit maximum number of clients
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket); // Actual waiting
}
catch (Exception ex)
{
throw new Exception("Server starting error" + ex);
}
}
// Here we go after receiving connection request
private void AcceptCallback(IAsyncResult ar)
{
try
{
Socket temp = (Socket)ar.AsyncState; // ??
Socket acceptedSocket = temp.EndAccept(ar); // Get socket of new client
ClientController.AddNewClient(acceptedSocket); // Handle new client
IPEndPoint REP = (IPEndPoint)acceptedSocket.RemoteEndPoint;
Console.WriteLine("Received request from IP:" + REP.Address.ToString() + "; port:" + REP.Port.ToString() + ";");
Console.WriteLine(ClientController.AllClients.Count() + " clients connected now");
Console.WriteLine();
// Resume waiting for new clients
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
}
catch (Exception ex)
{
throw new Exception("Server listening error" + ex);
}
}
}
Client class and Client collection:
// Client class
class Client
{
public int Id { get; private set; }
public Socket _clientSocket { get; private set; }
public ClientSender Sender { get; private set; }
public ClientReceiver Receive { get; private set; }
public Client(Socket socket, int id)
{
Sender = new ClientSender(socket, id);
Receive = new ClientReceiver(socket, id);
Receive.StartReceiving();
_clientSocket = socket;
Id = id;
}
// Handling client's request
public void HandleRequest(string request)
{
string cmd = request.Split('_');
// Here as an example I return points on sine wave based on user's request
double tSpan; double.TryParse(cmd[1], out tSpan);
int nPoints; int.TryParse(cmd[3], out nPoints);
double tStep = tSpan / nPoints;
for (int i = 0; i < nPoints; i++)
{
double ti = 0 + i * tStep;
double val = 10 * Math.Sin(2 * Math.PI * ti);
string DataToSend = "Точка (_" + ti.ToString() + "_,_" + val.ToString() + "_)";
Sender.AnswerRequest(DataToSend);
Thread.Sleep((int)(1000.0 * tStep));
}
}
}
// Class, which controlls all connected clients
static class ClientController
{
// All connected clients in a list
public static List<Client> AllClients = new List<Client>();
// Handling new client (accepting/denying connection)
public static void AddNewClient(Socket socket)
{
Client newClient = new Client(socket, AllClients.Count);
AllClients.Add(newClient);
}
// Removing client
public static void RemoveClient(int id)
{
int TargetClientIndex = AllClients.FindIndex(x => x.Id == id);
AllClients.RemoveAt(TargetClientIndex);
}
// Serving client request (accepting/denying it)
public static void AddClientRequest(int id, string data)
{
int TargetClientIndex = AllClients.FindIndex(x => x.Id == id);
AllClients.ElementAt(TargetClientIndex).HandleRequest(data);
}
}
And communications with clients:
// Class for receiving messages from client
public class ClientReceiver
{
private byte _buffer;
private Socket _receiveSocket;
private int _clientId;
public ClientReceiver(Socket receiveSocket, int Id)
{
_receiveSocket = receiveSocket;
_clientId = Id;
}
// Start waiting for message from client
public void StartReceiving()
{
try
{
_buffer = new byte[4];
_receiveSocket.BeginReceive(_buffer, 0, _buffer.Length, 0, ReceiveCallback, null);
}
catch (Exception ex)
{
throw new Exception("Receiving start error" + ex);
}
}
// Receiving message
private void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_receiveSocket.EndReceive(AR) > 1)
{
// First 4 bytes store the size of incoming messages - read them
int MessageLength = BitConverter.ToInt32(_buffer, 0);
// Knowing the full size of incoming message - prepare for receiving
_buffer = new byte[MessageLength];
// Receive
_receiveSocket.Receive(_buffer, MessageLength, SocketFlags.None);
string data = Encoding.Unicode.GetString(_buffer);
Console.WriteLine("User " + _clientId.ToString() + " sent following request: " + data);
// Send received message for handling
ClientController.AddClientRequest(_clientId, data);
// Resume waiting for new message
StartReceiving();
}
// if we didn't receive anything - disconnect client
else
{
Disconnect();
}
}
catch
{
if (!_receiveSocket.Connected)
{
Disconnect();
}
else
{
Console.WriteLine("Data receive error");
StartReceiving();
}
}
}
// Disconnecting client
private void Disconnect()
{
// Close connection
_receiveSocket.Disconnect(true);
ClientController.RemoveClient(_clientId);
}
}
// Class, used to send messages back to selected client
class ClientSender
{
private Socket _senderSocket;
private int _clientId;
public ClientSender(Socket receiveSocket, int Id)
{
_senderSocket = receiveSocket;
_clientId = Id;
}
// Sending message to client
public void AnswerRequest(string data)
{
try
{
byte DataPart = Encoding.Unicode.GetBytes(data);
int SendMsgLength = DataPart.Length;
byte InfoPart = BitConverter.GetBytes(SendMsgLength);
var fullPacket = new List<byte>();
fullPacket.AddRange(InfoPart);
fullPacket.AddRange(DataPart);
_senderSocket.Send(fullPacket.ToArray());
}
catch (Exception ex)
{
throw new Exception("Data sending error" + ex);
}
}
// Disconnecting client
private void Disconnect()
{
// Close connection
_senderSocket.Disconnect(true);
ClientController.RemoveClient(_clientId);
}
}
On the client side:
GUI part:
public delegate void UpdateCallback(string message);
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ConnectClick(object sender, EventArgs e)
{
IPHostEntry iph = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverAddress = iph.AddressList[1];
int server_Port = 1337;
Connection.TryToConnect(serverAddress, server_Port);
Connection.NewDataReceived += Foo_Changed;
data_outp.Items.Add("Connection Succesfull");
}
private void SendClick(object sender, EventArgs e)
{
double tSpan; double.TryParse(tSpan_input.Text, out tSpan);
int nPoints; int.TryParse(nPoints_input.Text, out nPoints);
string DataToSend = "PLS GIMME THIS tSpan=_" + tSpan.ToString() + "_ nPoints=_" + nPoints.ToString();
Connection.SendRequest(DataToSend);
}
private void Update(string message)
{
data_outp.Items.Add(message);
}
public void Foo_Changed(object sender, MyEventArgs args) // the Handler (reacts)
{
data_outp.Dispatcher.Invoke(new UpdateCallback(Update), new object { args.Message });
}
}
Interaction with server:
static class Connection
{
public static Socket _connectingSocket { get; private set; }
public static IPAddress ipAddress { get; private set; }
public static int Port { get; private set; }
public static string ReceivedData { get; private set; }
private static byte _buffer;
public static event EventHandler<MyEventArgs> NewDataReceived;
// Trying connecting to selected server
public static void TryToConnect(IPAddress ServerIp, int ServerPort)
{
ipAddress = ServerIp;
Port = ServerPort;
_connectingSocket = new Socket(ServerIp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
while (!_connectingSocket.Connected)
{
Thread.Sleep(100);
try
{
_connectingSocket.Connect(new IPEndPoint(ipAddress, Port));
StartReceiving();
}
catch (Exception ex)
{
throw new Exception("Connection error" + ex);
}
}
}
// Start waiting for message from client
public static void StartReceiving()
{
try
{
_buffer = new byte[4];
_connectingSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null);
}
catch (Exception ex)
{
throw new Exception("Receiving start error" + ex);
}
}
// Receiving message
private static void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_connectingSocket.EndReceive(AR) > 1)
{
// First 4 bytes store the size of incoming messages - read them
int MessageLength = BitConverter.ToInt32(_buffer, 0);
// Knowing the full size of incoming message - prepare for receiving
_buffer = new byte[MessageLength];
// Receive
_connectingSocket.Receive(_buffer, _buffer.Length, SocketFlags.None);
// Handle
ReceivedData = Encoding.Unicode.GetString(_buffer, 0, MessageLength);
if (ReceivedData.Length != 0)
NewDataReceived?.Invoke(null, new MyEventArgs(null, ReceivedData));
// Resume waiting for new message
StartReceiving();
}
else
{
// Received nothing
}
}
catch (Exception ex)
{
throw new Exception("Data receive error" + ex);
}
}
// Send message to server
public static void SendRequest(string DataToSend)
{
try
{
byte DataPart = Encoding.Unicode.GetBytes(DataToSend);
int SendMsgLength = DataPart.Length;
byte InfoPart = BitConverter.GetBytes(SendMsgLength);
var fullPacket = new List<byte>();
fullPacket.AddRange(InfoPart);
fullPacket.AddRange(DataPart);
_connectingSocket.Send(fullPacket.ToArray());
Console.WriteLine("Sending request: " + DataToSend);
Console.WriteLine("Infobytes length=" + InfoPart.Length + " bytes ; Total message length=" + SendMsgLength.ToString() + " bytes;");
}
catch (Exception ex)
{
throw new Exception("Data send error" + ex);
}
}
}
And an event to pass received data back to main GUI thread:
// My event to pass received message
public class MyEventArgs : EventArgs
{
public MyEventArgs(Exception ex, string msg)
{
Error = ex;
Message = msg;
}
public Exception Error { get; }
public string Message { get; }
}
It does everything I need as of now (I can plot/save data and all that) but i guess there's room for improvement. Especially on the client side - I don't really like that event driven part, but couldn't make true async data pass.
c# beginner socket server client
add a comment |
up vote
4
down vote
favorite
I wanted to try C# network programming and wrote this simple client/server application. The idea is - many clients can connect to server and request some data. As an example they request a set of points on sine-wave (required number of points and time span is up to each user).
The server then calculates required points and sends them to each user.
As this is my first program of that kind (and because I frankensteined it from 2 different examples) I guess there are definitely errors/smell here and I would be really grateful to hear them.
First - server setup:
class Program
{
static void Main(string args)
{
IPHostEntry iph = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverAddress = iph.AddressList[1];
int server_Port = 1337;
int maxConnections = 10;
Listener listener = new Listener(serverAddress, server_Port); // Setup server
listener.StartListening(maxConnections); // Start server
Console.Read();
}
}
// Here we accept new connections
class Listener
{
//This is the socket that will listen to any incoming connections
public Socket _serverSocket { get; private set; }
public int Port { get; private set; }
public int maxConnections { get; private set; }
public IPAddress ipAddress { get; private set; }
public Listener(IPAddress ServerIp, int ServerPort)
{
ipAddress = ServerIp;
Port = ServerPort;
_serverSocket = new Socket(ServerIp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
// Here we start waiting for new client
public void StartListening(int MaxConnections)
{
maxConnections = MaxConnections;
try
{
Console.WriteLine("Server started at IP:" + ipAddress.ToString() + "; port:" + Port.ToString() + ";n");
_serverSocket.Bind(new IPEndPoint(ipAddress, Port)); // Setup server at selected endpoint
_serverSocket.Listen(MaxConnections); // Limit maximum number of clients
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket); // Actual waiting
}
catch (Exception ex)
{
throw new Exception("Server starting error" + ex);
}
}
// Here we go after receiving connection request
private void AcceptCallback(IAsyncResult ar)
{
try
{
Socket temp = (Socket)ar.AsyncState; // ??
Socket acceptedSocket = temp.EndAccept(ar); // Get socket of new client
ClientController.AddNewClient(acceptedSocket); // Handle new client
IPEndPoint REP = (IPEndPoint)acceptedSocket.RemoteEndPoint;
Console.WriteLine("Received request from IP:" + REP.Address.ToString() + "; port:" + REP.Port.ToString() + ";");
Console.WriteLine(ClientController.AllClients.Count() + " clients connected now");
Console.WriteLine();
// Resume waiting for new clients
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
}
catch (Exception ex)
{
throw new Exception("Server listening error" + ex);
}
}
}
Client class and Client collection:
// Client class
class Client
{
public int Id { get; private set; }
public Socket _clientSocket { get; private set; }
public ClientSender Sender { get; private set; }
public ClientReceiver Receive { get; private set; }
public Client(Socket socket, int id)
{
Sender = new ClientSender(socket, id);
Receive = new ClientReceiver(socket, id);
Receive.StartReceiving();
_clientSocket = socket;
Id = id;
}
// Handling client's request
public void HandleRequest(string request)
{
string cmd = request.Split('_');
// Here as an example I return points on sine wave based on user's request
double tSpan; double.TryParse(cmd[1], out tSpan);
int nPoints; int.TryParse(cmd[3], out nPoints);
double tStep = tSpan / nPoints;
for (int i = 0; i < nPoints; i++)
{
double ti = 0 + i * tStep;
double val = 10 * Math.Sin(2 * Math.PI * ti);
string DataToSend = "Точка (_" + ti.ToString() + "_,_" + val.ToString() + "_)";
Sender.AnswerRequest(DataToSend);
Thread.Sleep((int)(1000.0 * tStep));
}
}
}
// Class, which controlls all connected clients
static class ClientController
{
// All connected clients in a list
public static List<Client> AllClients = new List<Client>();
// Handling new client (accepting/denying connection)
public static void AddNewClient(Socket socket)
{
Client newClient = new Client(socket, AllClients.Count);
AllClients.Add(newClient);
}
// Removing client
public static void RemoveClient(int id)
{
int TargetClientIndex = AllClients.FindIndex(x => x.Id == id);
AllClients.RemoveAt(TargetClientIndex);
}
// Serving client request (accepting/denying it)
public static void AddClientRequest(int id, string data)
{
int TargetClientIndex = AllClients.FindIndex(x => x.Id == id);
AllClients.ElementAt(TargetClientIndex).HandleRequest(data);
}
}
And communications with clients:
// Class for receiving messages from client
public class ClientReceiver
{
private byte _buffer;
private Socket _receiveSocket;
private int _clientId;
public ClientReceiver(Socket receiveSocket, int Id)
{
_receiveSocket = receiveSocket;
_clientId = Id;
}
// Start waiting for message from client
public void StartReceiving()
{
try
{
_buffer = new byte[4];
_receiveSocket.BeginReceive(_buffer, 0, _buffer.Length, 0, ReceiveCallback, null);
}
catch (Exception ex)
{
throw new Exception("Receiving start error" + ex);
}
}
// Receiving message
private void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_receiveSocket.EndReceive(AR) > 1)
{
// First 4 bytes store the size of incoming messages - read them
int MessageLength = BitConverter.ToInt32(_buffer, 0);
// Knowing the full size of incoming message - prepare for receiving
_buffer = new byte[MessageLength];
// Receive
_receiveSocket.Receive(_buffer, MessageLength, SocketFlags.None);
string data = Encoding.Unicode.GetString(_buffer);
Console.WriteLine("User " + _clientId.ToString() + " sent following request: " + data);
// Send received message for handling
ClientController.AddClientRequest(_clientId, data);
// Resume waiting for new message
StartReceiving();
}
// if we didn't receive anything - disconnect client
else
{
Disconnect();
}
}
catch
{
if (!_receiveSocket.Connected)
{
Disconnect();
}
else
{
Console.WriteLine("Data receive error");
StartReceiving();
}
}
}
// Disconnecting client
private void Disconnect()
{
// Close connection
_receiveSocket.Disconnect(true);
ClientController.RemoveClient(_clientId);
}
}
// Class, used to send messages back to selected client
class ClientSender
{
private Socket _senderSocket;
private int _clientId;
public ClientSender(Socket receiveSocket, int Id)
{
_senderSocket = receiveSocket;
_clientId = Id;
}
// Sending message to client
public void AnswerRequest(string data)
{
try
{
byte DataPart = Encoding.Unicode.GetBytes(data);
int SendMsgLength = DataPart.Length;
byte InfoPart = BitConverter.GetBytes(SendMsgLength);
var fullPacket = new List<byte>();
fullPacket.AddRange(InfoPart);
fullPacket.AddRange(DataPart);
_senderSocket.Send(fullPacket.ToArray());
}
catch (Exception ex)
{
throw new Exception("Data sending error" + ex);
}
}
// Disconnecting client
private void Disconnect()
{
// Close connection
_senderSocket.Disconnect(true);
ClientController.RemoveClient(_clientId);
}
}
On the client side:
GUI part:
public delegate void UpdateCallback(string message);
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ConnectClick(object sender, EventArgs e)
{
IPHostEntry iph = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverAddress = iph.AddressList[1];
int server_Port = 1337;
Connection.TryToConnect(serverAddress, server_Port);
Connection.NewDataReceived += Foo_Changed;
data_outp.Items.Add("Connection Succesfull");
}
private void SendClick(object sender, EventArgs e)
{
double tSpan; double.TryParse(tSpan_input.Text, out tSpan);
int nPoints; int.TryParse(nPoints_input.Text, out nPoints);
string DataToSend = "PLS GIMME THIS tSpan=_" + tSpan.ToString() + "_ nPoints=_" + nPoints.ToString();
Connection.SendRequest(DataToSend);
}
private void Update(string message)
{
data_outp.Items.Add(message);
}
public void Foo_Changed(object sender, MyEventArgs args) // the Handler (reacts)
{
data_outp.Dispatcher.Invoke(new UpdateCallback(Update), new object { args.Message });
}
}
Interaction with server:
static class Connection
{
public static Socket _connectingSocket { get; private set; }
public static IPAddress ipAddress { get; private set; }
public static int Port { get; private set; }
public static string ReceivedData { get; private set; }
private static byte _buffer;
public static event EventHandler<MyEventArgs> NewDataReceived;
// Trying connecting to selected server
public static void TryToConnect(IPAddress ServerIp, int ServerPort)
{
ipAddress = ServerIp;
Port = ServerPort;
_connectingSocket = new Socket(ServerIp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
while (!_connectingSocket.Connected)
{
Thread.Sleep(100);
try
{
_connectingSocket.Connect(new IPEndPoint(ipAddress, Port));
StartReceiving();
}
catch (Exception ex)
{
throw new Exception("Connection error" + ex);
}
}
}
// Start waiting for message from client
public static void StartReceiving()
{
try
{
_buffer = new byte[4];
_connectingSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null);
}
catch (Exception ex)
{
throw new Exception("Receiving start error" + ex);
}
}
// Receiving message
private static void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_connectingSocket.EndReceive(AR) > 1)
{
// First 4 bytes store the size of incoming messages - read them
int MessageLength = BitConverter.ToInt32(_buffer, 0);
// Knowing the full size of incoming message - prepare for receiving
_buffer = new byte[MessageLength];
// Receive
_connectingSocket.Receive(_buffer, _buffer.Length, SocketFlags.None);
// Handle
ReceivedData = Encoding.Unicode.GetString(_buffer, 0, MessageLength);
if (ReceivedData.Length != 0)
NewDataReceived?.Invoke(null, new MyEventArgs(null, ReceivedData));
// Resume waiting for new message
StartReceiving();
}
else
{
// Received nothing
}
}
catch (Exception ex)
{
throw new Exception("Data receive error" + ex);
}
}
// Send message to server
public static void SendRequest(string DataToSend)
{
try
{
byte DataPart = Encoding.Unicode.GetBytes(DataToSend);
int SendMsgLength = DataPart.Length;
byte InfoPart = BitConverter.GetBytes(SendMsgLength);
var fullPacket = new List<byte>();
fullPacket.AddRange(InfoPart);
fullPacket.AddRange(DataPart);
_connectingSocket.Send(fullPacket.ToArray());
Console.WriteLine("Sending request: " + DataToSend);
Console.WriteLine("Infobytes length=" + InfoPart.Length + " bytes ; Total message length=" + SendMsgLength.ToString() + " bytes;");
}
catch (Exception ex)
{
throw new Exception("Data send error" + ex);
}
}
}
And an event to pass received data back to main GUI thread:
// My event to pass received message
public class MyEventArgs : EventArgs
{
public MyEventArgs(Exception ex, string msg)
{
Error = ex;
Message = msg;
}
public Exception Error { get; }
public string Message { get; }
}
It does everything I need as of now (I can plot/save data and all that) but i guess there's room for improvement. Especially on the client side - I don't really like that event driven part, but couldn't make true async data pass.
c# beginner socket server client
add a comment |
up vote
4
down vote
favorite
up vote
4
down vote
favorite
I wanted to try C# network programming and wrote this simple client/server application. The idea is - many clients can connect to server and request some data. As an example they request a set of points on sine-wave (required number of points and time span is up to each user).
The server then calculates required points and sends them to each user.
As this is my first program of that kind (and because I frankensteined it from 2 different examples) I guess there are definitely errors/smell here and I would be really grateful to hear them.
First - server setup:
class Program
{
static void Main(string args)
{
IPHostEntry iph = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverAddress = iph.AddressList[1];
int server_Port = 1337;
int maxConnections = 10;
Listener listener = new Listener(serverAddress, server_Port); // Setup server
listener.StartListening(maxConnections); // Start server
Console.Read();
}
}
// Here we accept new connections
class Listener
{
//This is the socket that will listen to any incoming connections
public Socket _serverSocket { get; private set; }
public int Port { get; private set; }
public int maxConnections { get; private set; }
public IPAddress ipAddress { get; private set; }
public Listener(IPAddress ServerIp, int ServerPort)
{
ipAddress = ServerIp;
Port = ServerPort;
_serverSocket = new Socket(ServerIp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
// Here we start waiting for new client
public void StartListening(int MaxConnections)
{
maxConnections = MaxConnections;
try
{
Console.WriteLine("Server started at IP:" + ipAddress.ToString() + "; port:" + Port.ToString() + ";n");
_serverSocket.Bind(new IPEndPoint(ipAddress, Port)); // Setup server at selected endpoint
_serverSocket.Listen(MaxConnections); // Limit maximum number of clients
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket); // Actual waiting
}
catch (Exception ex)
{
throw new Exception("Server starting error" + ex);
}
}
// Here we go after receiving connection request
private void AcceptCallback(IAsyncResult ar)
{
try
{
Socket temp = (Socket)ar.AsyncState; // ??
Socket acceptedSocket = temp.EndAccept(ar); // Get socket of new client
ClientController.AddNewClient(acceptedSocket); // Handle new client
IPEndPoint REP = (IPEndPoint)acceptedSocket.RemoteEndPoint;
Console.WriteLine("Received request from IP:" + REP.Address.ToString() + "; port:" + REP.Port.ToString() + ";");
Console.WriteLine(ClientController.AllClients.Count() + " clients connected now");
Console.WriteLine();
// Resume waiting for new clients
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
}
catch (Exception ex)
{
throw new Exception("Server listening error" + ex);
}
}
}
Client class and Client collection:
// Client class
class Client
{
public int Id { get; private set; }
public Socket _clientSocket { get; private set; }
public ClientSender Sender { get; private set; }
public ClientReceiver Receive { get; private set; }
public Client(Socket socket, int id)
{
Sender = new ClientSender(socket, id);
Receive = new ClientReceiver(socket, id);
Receive.StartReceiving();
_clientSocket = socket;
Id = id;
}
// Handling client's request
public void HandleRequest(string request)
{
string cmd = request.Split('_');
// Here as an example I return points on sine wave based on user's request
double tSpan; double.TryParse(cmd[1], out tSpan);
int nPoints; int.TryParse(cmd[3], out nPoints);
double tStep = tSpan / nPoints;
for (int i = 0; i < nPoints; i++)
{
double ti = 0 + i * tStep;
double val = 10 * Math.Sin(2 * Math.PI * ti);
string DataToSend = "Точка (_" + ti.ToString() + "_,_" + val.ToString() + "_)";
Sender.AnswerRequest(DataToSend);
Thread.Sleep((int)(1000.0 * tStep));
}
}
}
// Class, which controlls all connected clients
static class ClientController
{
// All connected clients in a list
public static List<Client> AllClients = new List<Client>();
// Handling new client (accepting/denying connection)
public static void AddNewClient(Socket socket)
{
Client newClient = new Client(socket, AllClients.Count);
AllClients.Add(newClient);
}
// Removing client
public static void RemoveClient(int id)
{
int TargetClientIndex = AllClients.FindIndex(x => x.Id == id);
AllClients.RemoveAt(TargetClientIndex);
}
// Serving client request (accepting/denying it)
public static void AddClientRequest(int id, string data)
{
int TargetClientIndex = AllClients.FindIndex(x => x.Id == id);
AllClients.ElementAt(TargetClientIndex).HandleRequest(data);
}
}
And communications with clients:
// Class for receiving messages from client
public class ClientReceiver
{
private byte _buffer;
private Socket _receiveSocket;
private int _clientId;
public ClientReceiver(Socket receiveSocket, int Id)
{
_receiveSocket = receiveSocket;
_clientId = Id;
}
// Start waiting for message from client
public void StartReceiving()
{
try
{
_buffer = new byte[4];
_receiveSocket.BeginReceive(_buffer, 0, _buffer.Length, 0, ReceiveCallback, null);
}
catch (Exception ex)
{
throw new Exception("Receiving start error" + ex);
}
}
// Receiving message
private void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_receiveSocket.EndReceive(AR) > 1)
{
// First 4 bytes store the size of incoming messages - read them
int MessageLength = BitConverter.ToInt32(_buffer, 0);
// Knowing the full size of incoming message - prepare for receiving
_buffer = new byte[MessageLength];
// Receive
_receiveSocket.Receive(_buffer, MessageLength, SocketFlags.None);
string data = Encoding.Unicode.GetString(_buffer);
Console.WriteLine("User " + _clientId.ToString() + " sent following request: " + data);
// Send received message for handling
ClientController.AddClientRequest(_clientId, data);
// Resume waiting for new message
StartReceiving();
}
// if we didn't receive anything - disconnect client
else
{
Disconnect();
}
}
catch
{
if (!_receiveSocket.Connected)
{
Disconnect();
}
else
{
Console.WriteLine("Data receive error");
StartReceiving();
}
}
}
// Disconnecting client
private void Disconnect()
{
// Close connection
_receiveSocket.Disconnect(true);
ClientController.RemoveClient(_clientId);
}
}
// Class, used to send messages back to selected client
class ClientSender
{
private Socket _senderSocket;
private int _clientId;
public ClientSender(Socket receiveSocket, int Id)
{
_senderSocket = receiveSocket;
_clientId = Id;
}
// Sending message to client
public void AnswerRequest(string data)
{
try
{
byte DataPart = Encoding.Unicode.GetBytes(data);
int SendMsgLength = DataPart.Length;
byte InfoPart = BitConverter.GetBytes(SendMsgLength);
var fullPacket = new List<byte>();
fullPacket.AddRange(InfoPart);
fullPacket.AddRange(DataPart);
_senderSocket.Send(fullPacket.ToArray());
}
catch (Exception ex)
{
throw new Exception("Data sending error" + ex);
}
}
// Disconnecting client
private void Disconnect()
{
// Close connection
_senderSocket.Disconnect(true);
ClientController.RemoveClient(_clientId);
}
}
On the client side:
GUI part:
public delegate void UpdateCallback(string message);
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ConnectClick(object sender, EventArgs e)
{
IPHostEntry iph = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverAddress = iph.AddressList[1];
int server_Port = 1337;
Connection.TryToConnect(serverAddress, server_Port);
Connection.NewDataReceived += Foo_Changed;
data_outp.Items.Add("Connection Succesfull");
}
private void SendClick(object sender, EventArgs e)
{
double tSpan; double.TryParse(tSpan_input.Text, out tSpan);
int nPoints; int.TryParse(nPoints_input.Text, out nPoints);
string DataToSend = "PLS GIMME THIS tSpan=_" + tSpan.ToString() + "_ nPoints=_" + nPoints.ToString();
Connection.SendRequest(DataToSend);
}
private void Update(string message)
{
data_outp.Items.Add(message);
}
public void Foo_Changed(object sender, MyEventArgs args) // the Handler (reacts)
{
data_outp.Dispatcher.Invoke(new UpdateCallback(Update), new object { args.Message });
}
}
Interaction with server:
static class Connection
{
public static Socket _connectingSocket { get; private set; }
public static IPAddress ipAddress { get; private set; }
public static int Port { get; private set; }
public static string ReceivedData { get; private set; }
private static byte _buffer;
public static event EventHandler<MyEventArgs> NewDataReceived;
// Trying connecting to selected server
public static void TryToConnect(IPAddress ServerIp, int ServerPort)
{
ipAddress = ServerIp;
Port = ServerPort;
_connectingSocket = new Socket(ServerIp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
while (!_connectingSocket.Connected)
{
Thread.Sleep(100);
try
{
_connectingSocket.Connect(new IPEndPoint(ipAddress, Port));
StartReceiving();
}
catch (Exception ex)
{
throw new Exception("Connection error" + ex);
}
}
}
// Start waiting for message from client
public static void StartReceiving()
{
try
{
_buffer = new byte[4];
_connectingSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null);
}
catch (Exception ex)
{
throw new Exception("Receiving start error" + ex);
}
}
// Receiving message
private static void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_connectingSocket.EndReceive(AR) > 1)
{
// First 4 bytes store the size of incoming messages - read them
int MessageLength = BitConverter.ToInt32(_buffer, 0);
// Knowing the full size of incoming message - prepare for receiving
_buffer = new byte[MessageLength];
// Receive
_connectingSocket.Receive(_buffer, _buffer.Length, SocketFlags.None);
// Handle
ReceivedData = Encoding.Unicode.GetString(_buffer, 0, MessageLength);
if (ReceivedData.Length != 0)
NewDataReceived?.Invoke(null, new MyEventArgs(null, ReceivedData));
// Resume waiting for new message
StartReceiving();
}
else
{
// Received nothing
}
}
catch (Exception ex)
{
throw new Exception("Data receive error" + ex);
}
}
// Send message to server
public static void SendRequest(string DataToSend)
{
try
{
byte DataPart = Encoding.Unicode.GetBytes(DataToSend);
int SendMsgLength = DataPart.Length;
byte InfoPart = BitConverter.GetBytes(SendMsgLength);
var fullPacket = new List<byte>();
fullPacket.AddRange(InfoPart);
fullPacket.AddRange(DataPart);
_connectingSocket.Send(fullPacket.ToArray());
Console.WriteLine("Sending request: " + DataToSend);
Console.WriteLine("Infobytes length=" + InfoPart.Length + " bytes ; Total message length=" + SendMsgLength.ToString() + " bytes;");
}
catch (Exception ex)
{
throw new Exception("Data send error" + ex);
}
}
}
And an event to pass received data back to main GUI thread:
// My event to pass received message
public class MyEventArgs : EventArgs
{
public MyEventArgs(Exception ex, string msg)
{
Error = ex;
Message = msg;
}
public Exception Error { get; }
public string Message { get; }
}
It does everything I need as of now (I can plot/save data and all that) but i guess there's room for improvement. Especially on the client side - I don't really like that event driven part, but couldn't make true async data pass.
c# beginner socket server client
I wanted to try C# network programming and wrote this simple client/server application. The idea is - many clients can connect to server and request some data. As an example they request a set of points on sine-wave (required number of points and time span is up to each user).
The server then calculates required points and sends them to each user.
As this is my first program of that kind (and because I frankensteined it from 2 different examples) I guess there are definitely errors/smell here and I would be really grateful to hear them.
First - server setup:
class Program
{
static void Main(string args)
{
IPHostEntry iph = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverAddress = iph.AddressList[1];
int server_Port = 1337;
int maxConnections = 10;
Listener listener = new Listener(serverAddress, server_Port); // Setup server
listener.StartListening(maxConnections); // Start server
Console.Read();
}
}
// Here we accept new connections
class Listener
{
//This is the socket that will listen to any incoming connections
public Socket _serverSocket { get; private set; }
public int Port { get; private set; }
public int maxConnections { get; private set; }
public IPAddress ipAddress { get; private set; }
public Listener(IPAddress ServerIp, int ServerPort)
{
ipAddress = ServerIp;
Port = ServerPort;
_serverSocket = new Socket(ServerIp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
// Here we start waiting for new client
public void StartListening(int MaxConnections)
{
maxConnections = MaxConnections;
try
{
Console.WriteLine("Server started at IP:" + ipAddress.ToString() + "; port:" + Port.ToString() + ";n");
_serverSocket.Bind(new IPEndPoint(ipAddress, Port)); // Setup server at selected endpoint
_serverSocket.Listen(MaxConnections); // Limit maximum number of clients
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket); // Actual waiting
}
catch (Exception ex)
{
throw new Exception("Server starting error" + ex);
}
}
// Here we go after receiving connection request
private void AcceptCallback(IAsyncResult ar)
{
try
{
Socket temp = (Socket)ar.AsyncState; // ??
Socket acceptedSocket = temp.EndAccept(ar); // Get socket of new client
ClientController.AddNewClient(acceptedSocket); // Handle new client
IPEndPoint REP = (IPEndPoint)acceptedSocket.RemoteEndPoint;
Console.WriteLine("Received request from IP:" + REP.Address.ToString() + "; port:" + REP.Port.ToString() + ";");
Console.WriteLine(ClientController.AllClients.Count() + " clients connected now");
Console.WriteLine();
// Resume waiting for new clients
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
}
catch (Exception ex)
{
throw new Exception("Server listening error" + ex);
}
}
}
Client class and Client collection:
// Client class
class Client
{
public int Id { get; private set; }
public Socket _clientSocket { get; private set; }
public ClientSender Sender { get; private set; }
public ClientReceiver Receive { get; private set; }
public Client(Socket socket, int id)
{
Sender = new ClientSender(socket, id);
Receive = new ClientReceiver(socket, id);
Receive.StartReceiving();
_clientSocket = socket;
Id = id;
}
// Handling client's request
public void HandleRequest(string request)
{
string cmd = request.Split('_');
// Here as an example I return points on sine wave based on user's request
double tSpan; double.TryParse(cmd[1], out tSpan);
int nPoints; int.TryParse(cmd[3], out nPoints);
double tStep = tSpan / nPoints;
for (int i = 0; i < nPoints; i++)
{
double ti = 0 + i * tStep;
double val = 10 * Math.Sin(2 * Math.PI * ti);
string DataToSend = "Точка (_" + ti.ToString() + "_,_" + val.ToString() + "_)";
Sender.AnswerRequest(DataToSend);
Thread.Sleep((int)(1000.0 * tStep));
}
}
}
// Class, which controlls all connected clients
static class ClientController
{
// All connected clients in a list
public static List<Client> AllClients = new List<Client>();
// Handling new client (accepting/denying connection)
public static void AddNewClient(Socket socket)
{
Client newClient = new Client(socket, AllClients.Count);
AllClients.Add(newClient);
}
// Removing client
public static void RemoveClient(int id)
{
int TargetClientIndex = AllClients.FindIndex(x => x.Id == id);
AllClients.RemoveAt(TargetClientIndex);
}
// Serving client request (accepting/denying it)
public static void AddClientRequest(int id, string data)
{
int TargetClientIndex = AllClients.FindIndex(x => x.Id == id);
AllClients.ElementAt(TargetClientIndex).HandleRequest(data);
}
}
And communications with clients:
// Class for receiving messages from client
public class ClientReceiver
{
private byte _buffer;
private Socket _receiveSocket;
private int _clientId;
public ClientReceiver(Socket receiveSocket, int Id)
{
_receiveSocket = receiveSocket;
_clientId = Id;
}
// Start waiting for message from client
public void StartReceiving()
{
try
{
_buffer = new byte[4];
_receiveSocket.BeginReceive(_buffer, 0, _buffer.Length, 0, ReceiveCallback, null);
}
catch (Exception ex)
{
throw new Exception("Receiving start error" + ex);
}
}
// Receiving message
private void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_receiveSocket.EndReceive(AR) > 1)
{
// First 4 bytes store the size of incoming messages - read them
int MessageLength = BitConverter.ToInt32(_buffer, 0);
// Knowing the full size of incoming message - prepare for receiving
_buffer = new byte[MessageLength];
// Receive
_receiveSocket.Receive(_buffer, MessageLength, SocketFlags.None);
string data = Encoding.Unicode.GetString(_buffer);
Console.WriteLine("User " + _clientId.ToString() + " sent following request: " + data);
// Send received message for handling
ClientController.AddClientRequest(_clientId, data);
// Resume waiting for new message
StartReceiving();
}
// if we didn't receive anything - disconnect client
else
{
Disconnect();
}
}
catch
{
if (!_receiveSocket.Connected)
{
Disconnect();
}
else
{
Console.WriteLine("Data receive error");
StartReceiving();
}
}
}
// Disconnecting client
private void Disconnect()
{
// Close connection
_receiveSocket.Disconnect(true);
ClientController.RemoveClient(_clientId);
}
}
// Class, used to send messages back to selected client
class ClientSender
{
private Socket _senderSocket;
private int _clientId;
public ClientSender(Socket receiveSocket, int Id)
{
_senderSocket = receiveSocket;
_clientId = Id;
}
// Sending message to client
public void AnswerRequest(string data)
{
try
{
byte DataPart = Encoding.Unicode.GetBytes(data);
int SendMsgLength = DataPart.Length;
byte InfoPart = BitConverter.GetBytes(SendMsgLength);
var fullPacket = new List<byte>();
fullPacket.AddRange(InfoPart);
fullPacket.AddRange(DataPart);
_senderSocket.Send(fullPacket.ToArray());
}
catch (Exception ex)
{
throw new Exception("Data sending error" + ex);
}
}
// Disconnecting client
private void Disconnect()
{
// Close connection
_senderSocket.Disconnect(true);
ClientController.RemoveClient(_clientId);
}
}
On the client side:
GUI part:
public delegate void UpdateCallback(string message);
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ConnectClick(object sender, EventArgs e)
{
IPHostEntry iph = Dns.GetHostEntry(Dns.GetHostName());
IPAddress serverAddress = iph.AddressList[1];
int server_Port = 1337;
Connection.TryToConnect(serverAddress, server_Port);
Connection.NewDataReceived += Foo_Changed;
data_outp.Items.Add("Connection Succesfull");
}
private void SendClick(object sender, EventArgs e)
{
double tSpan; double.TryParse(tSpan_input.Text, out tSpan);
int nPoints; int.TryParse(nPoints_input.Text, out nPoints);
string DataToSend = "PLS GIMME THIS tSpan=_" + tSpan.ToString() + "_ nPoints=_" + nPoints.ToString();
Connection.SendRequest(DataToSend);
}
private void Update(string message)
{
data_outp.Items.Add(message);
}
public void Foo_Changed(object sender, MyEventArgs args) // the Handler (reacts)
{
data_outp.Dispatcher.Invoke(new UpdateCallback(Update), new object { args.Message });
}
}
Interaction with server:
static class Connection
{
public static Socket _connectingSocket { get; private set; }
public static IPAddress ipAddress { get; private set; }
public static int Port { get; private set; }
public static string ReceivedData { get; private set; }
private static byte _buffer;
public static event EventHandler<MyEventArgs> NewDataReceived;
// Trying connecting to selected server
public static void TryToConnect(IPAddress ServerIp, int ServerPort)
{
ipAddress = ServerIp;
Port = ServerPort;
_connectingSocket = new Socket(ServerIp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
while (!_connectingSocket.Connected)
{
Thread.Sleep(100);
try
{
_connectingSocket.Connect(new IPEndPoint(ipAddress, Port));
StartReceiving();
}
catch (Exception ex)
{
throw new Exception("Connection error" + ex);
}
}
}
// Start waiting for message from client
public static void StartReceiving()
{
try
{
_buffer = new byte[4];
_connectingSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null);
}
catch (Exception ex)
{
throw new Exception("Receiving start error" + ex);
}
}
// Receiving message
private static void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_connectingSocket.EndReceive(AR) > 1)
{
// First 4 bytes store the size of incoming messages - read them
int MessageLength = BitConverter.ToInt32(_buffer, 0);
// Knowing the full size of incoming message - prepare for receiving
_buffer = new byte[MessageLength];
// Receive
_connectingSocket.Receive(_buffer, _buffer.Length, SocketFlags.None);
// Handle
ReceivedData = Encoding.Unicode.GetString(_buffer, 0, MessageLength);
if (ReceivedData.Length != 0)
NewDataReceived?.Invoke(null, new MyEventArgs(null, ReceivedData));
// Resume waiting for new message
StartReceiving();
}
else
{
// Received nothing
}
}
catch (Exception ex)
{
throw new Exception("Data receive error" + ex);
}
}
// Send message to server
public static void SendRequest(string DataToSend)
{
try
{
byte DataPart = Encoding.Unicode.GetBytes(DataToSend);
int SendMsgLength = DataPart.Length;
byte InfoPart = BitConverter.GetBytes(SendMsgLength);
var fullPacket = new List<byte>();
fullPacket.AddRange(InfoPart);
fullPacket.AddRange(DataPart);
_connectingSocket.Send(fullPacket.ToArray());
Console.WriteLine("Sending request: " + DataToSend);
Console.WriteLine("Infobytes length=" + InfoPart.Length + " bytes ; Total message length=" + SendMsgLength.ToString() + " bytes;");
}
catch (Exception ex)
{
throw new Exception("Data send error" + ex);
}
}
}
And an event to pass received data back to main GUI thread:
// My event to pass received message
public class MyEventArgs : EventArgs
{
public MyEventArgs(Exception ex, string msg)
{
Error = ex;
Message = msg;
}
public Exception Error { get; }
public string Message { get; }
}
It does everything I need as of now (I can plot/save data and all that) but i guess there's room for improvement. Especially on the client side - I don't really like that event driven part, but couldn't make true async data pass.
c# beginner socket server client
c# beginner socket server client
edited Nov 21 at 16:10
t3chb0t
33.8k745108
33.8k745108
asked Nov 21 at 15:11
Leinad
211
211
add a comment |
add a comment |
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208160%2fsocket-client-server-app-for-exchanging-sine-wave-points%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown