Server :
public class TcpServer
{
private TcpListener tcpListener;
private static ManualResetEvent allDone = new ManualResetEvent(false);
public TcpServer(string url, int port)
{
tcpListener = new TcpListener(IPAddress.Parse(url), port);
pingMapper = new LightPingMapper();
}
public void Run()
{
tcpListener.Start();
Console.WriteLine("Server running");
while (true)
{
allDone.Reset();
tcpListener.BeginAcceptSocket(AcceptCallback, tcpListener);
Console.WriteLine("Accepting socket");
allDone.WaitOne();
}
Console.ReadLine();
}
private void AcceptCallback(IAsyncResult result)
{
try
{
allDone.Set();
var listener = (TcpListener) result.AsyncState;
var handler = listener.EndAcceptSocket(result);
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, state.buffer.Length, 0, ReadCallback, state);
}
catch (Exception e)
{
Console.WriteLine($"Error accepting callback. {e.Message}");
}
}
private void ReadCallback(IAsyncResult asyncResult)
{
try
{
string content = string.Empty;
Console.WriteLine("Read data from socket");
StateObject state = (StateObject) asyncResult.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(asyncResult);
if (bytesRead > 0)
{
state.sb.Append(Encoding.UTF8.GetString(state.buffer));
content = state.sb.ToString();
Console.WriteLine(content + " " + DateTime.Now);
}
}
catch (Exception e)
{
Console.WriteLine($"Error reading socket. {e.Message}");
}
}
}
class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
Client:
public class TCPClientWrapper
{
private TcpClient tcpClient;
private readonly string address;
private readonly int port;
public TCPClientWrapper(string address, int port)
{
InitTcpClient();
this.address = address;
this.port = port;
}
public void SendMessage()
{
for(int i=0; i < 10; i++)
{
if (!SocketConnected())
{
TryConnect();
}
byte[] buffer = Encoding.UTF8.GetBytes("Hello");
tcpClient.Client.Send(buffer);
Thread.Sleep(60000);
}
}
private void TryConnect()
{
bool isConnected = false;
while (true)
{
try
{
InitTcpClient();
tcpClient.Connect(IPAddress.Parse(address), port);
if (SocketConnected())
{
Console.WriteLine("TcpClient, Connected");
isConnected = true;
break;
}
}
catch (Exception e)
{
Console.WriteLine("TcpClient, connection failed. Try to reconnect after 30 seconds, {0}", e.Message);
}
finally
{
if (!isConnected)
{
tcpClient.Close();
Thread.Sleep(30000);
}
}
}
}
private void InitTcpClient()
{
tcpClient = new TcpClient();
tcpClient.SendTimeout = 15;
}
private bool SocketConnected()
{
var s = tcpClient.Client;
if (!s.Connected)
return false;
bool part1 = s.Poll(1000, SelectMode.SelectRead);
bool part2 = s.Available == 0;
return !(part1 && part2);
}
}
The problem is that server read only first message , each next message is not received by server . The tcpClient is connected , but server doesn't receive any message . Could anyone suggest what is wrong with my code ?
In ReadCallback, you don't start the next read - so yes, your code only reads once.
Adding
handler.BeginReceive(state.buffer, 0, state.buffer.Length, 0, ReadCallback, state);
to the bottom of ReadCallback (when bytesRead > 0) should work. However! You aren't implementing proper framing, so you should be very cautious of that. A basic framing implementation for a text-based protocol (like this) would be to use some kind of line-end sentinel, and buffer data until you see a line-end, then process the line.
On TCP, you are only guaranteed to get the right bytes in the right order (or a failed socket eventually) - you are not guaranteed to get them in the same composition in terms of calls to Send exactly matching calls to Receive in terms of the numbers of bytes in each.
so made client-server-client tcp/ip app in c# that are supposed to communicate between 2 computers that are in different network.
I have few problems , first of them my server wont start on my public ip sayings its not valid in this context. Second is that I need to press send button twice before it sends data to server ,and then server 2 variations of data, one in bytes, other in char how its supposed to be. And third is how to make clients trying to receive data whole time. Should I have connection between clients have open whole time? I tried using timers to check if there is data to be received from the server.
Server code
static void Main(string[] args)
{
TcpListener server = new TcpListener(IPAddress.Parse("192.168.0.13"), 8080);
TcpClient client = default(TcpClient);
TcpClient client2 = default(TcpClient)
try
{
server.Start();
Console.WriteLine("Server started...");
}
catch(Exception ex)
{
Console.WriteLine("Server failed to start... {0}",ex.ToString());
Console.Read();
}
while (true)
{
client = server.AcceptTcpClient(); /
byte[] receivedBuffer = new byte[1000];
NetworkStream stream = client.GetStream();
stream.Read(receivedBuffer,0,receivedBuffer.Length);
StringBuilder message = new StringBuilder(); foreach (byte b in receivedBuffer)
{
if (b.Equals(126)
) //proveramo d {
break;
}
else
{
message.Append(Convert.ToChar(b).ToString()); }
}
client2 = server.AcceptTcpClient();
byte[] receivedBuffer2 = new byte[1000];
NetworkStream stream2 = client2.GetStream();
stream2.Read(receivedBuffer2, 0, receivedBuffer2.Length);
StringBuilder message2 = new StringBuilder();
foreach (byte g in receivedBuffer2)
{
if (g.Equals(126))
{
break;
}
else
{
message2.Append(g);
}
}
stream2.Write(receivedBuffer, 0, receivedBuffer.Length);
stream.Write(receivedBuffer2,0,receivedBuffer2.Length);
Console.WriteLine(message2.ToString());
Console.WriteLine(message.ToString());
}
Client code
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
timer1.Start();
}
private int port = 8080;
private void submit_Click(object sender, EventArgs e)
{
TcpClient client = new TcpClient("192.168.0.13",port);
TcpListener listener = new TcpListener(IPAddress.Parse("192.168.0.13"), port);
long byteCount = Encoding.ASCII.GetByteCount(messagebox_TB.Text + 1); byte[] sentDataBytes = new byte[byteCount];
sentDataBytes = Encoding.ASCII.GetBytes(messagebox_TB.Text + "~");
NetworkStream stream = client.GetStream();
stream.Write(sentDataBytes,0,sentDataBytes.Length);
stream.Close();
client.Close();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
long a = 0;
try
{
TcpClient client = new TcpClient("192.168.0.13", port);
TcpListener listener = new TcpListener(IPAddress.Parse("192.168.0.13"), port);
NetworkStream stream = client.GetStream();
byte[] receviedBytes = new byte[100];
stream.Read(receviedBytes, 0, receviedBytes.Length);
StringBuilder
message = new StringBuilder();
foreach (byte b in receviedBytes) {
if (b.Equals(126)
) //proveramo {
break;
}
else
{
message.Append(Convert.ToChar(b).ToString()); }
}
textBox1.Text = message.ToString();
client.Close();
stream.Close();
}
catch
{
a++;
}
}
}
My Client Source Code :
public partial class Form1 : Form
{
string serverip = "localHost";
int port = 160;
public Form1()
{
InitializeComponent();
}
private void Submit_Click(object sender, EventArgs e)
{
TcpClient client = new TcpClient(serverip, port);
int byteCount = Encoding.ASCII.GetByteCount(Message.Text);
byte[] sendData = new byte[byteCount];
sendData = Encoding.ASCII.GetBytes(Message.Text);
NetworkStream stream = client.GetStream();
stream.Write(sendData, 0, sendData.Length);
stream.Close();
client.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
My server
class Program
{
static void Main(string[] args)
{
IPAddress ip = Dns.GetHostEntry("localHost").AddressList[0];
TcpListener server = new TcpListener(ip, 160);
TcpClient client = default(TcpClient);
try
{
server.Start();
Console.WriteLine("The server has started successfully");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadLine();
}
while (true)
{
client = server.AcceptTcpClient();
byte[] receivedBuffer = new byte[100];
NetworkStream stream = client.GetStream();
stream.Read(receivedBuffer, 0, receivedBuffer.Length);
StringBuilder msg = new StringBuilder();
foreach (byte b in receivedBuffer)
{
if (b.Equals(59))
{
break;
}
else
{
msg.Append(Convert.ToChar(b).ToString());
}
}
Console.WriteLine(msg.ToString() + msg.Length);
}
}
}
Essentially i want make it so i can have multiple clients on the server sending a message from different ip addresses of course. I have been using c# a year now mostly in school and I am above average at best at it.
First time asking question so sorry if its in wrong format
I'm trying to built a server client application (wpf).
the structure I'm trying to accomplish is this:
a client that only sends data( a simple string) needs to be a wpf app.
a client that only receives data(a string from the sender client)
a server that transfer the data from the sender to the receiver (can be multiple senders and multiple receivers) can be a console
application.
One of the problems I'm facing is how do I separate the server role.
The second problem is how do I let the server know what type of client it's communicating with, a sender or a receiver.
this is my code:
Server:
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows;
namespace NetMessageServerWpf
{
public partial class MainWindow : Window
{
TcpClient client;
public MainWindow()
{
InitializeComponent();
this.tcpListener = new TcpListener(IPAddress.Any, 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void btnSend_Click(object sender, RoutedEventArgs e)
{
if(client == null || !client.Connected)
client = this.tcpListener.AcceptTcpClient();
msg = txtMessage.Text;
SendTCP(client);
}
public TcpListener tcpListener;
public Thread listenThread;
private string msg;
private void ListenForClients()
{
this.tcpListener.Start();
}
public void SendTCP(TcpClient tcpClient)
{
NetworkStream clientStream = tcpClient.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(this.msg);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
}
}
Client:
namespace NetClientSideWpf
{
class Client : Base
{
private string messageString;
public string MessageString
{
get { return messageString; }
set
{
messageString = value;
OnPropertyChanged("MessageString");
}
}
public Client()
{
ConnectToServer();
}
public void ConnectToServer()
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
Thread ServerThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
ServerThread.Start(client);
}
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try
{
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
break;
}
if (bytesRead == 0)
{
break;
}
ASCIIEncoding encoder = new ASCIIEncoding();
MessageString = encoder.GetString(message, 0, bytesRead);
}
}
}
}
Thanks in advance! :)
First off, I would wrap your clients in a Client object that you can call methods on.
Then, when a client connects, it should send out a message detailing its mode:
"IAm:Sender"
OR
"IAm:Reciever"
You could have the second part parse to an enum if you wanted. Then you would sort the Client objects based on the mode:
List<Client> clients;
client.Mode = Enum.Parse(typeof(ClientMode), message.Split(':')[1]);
clients.Add(client);
And when a "sender" sent a "Broadcast" message, you would write it to every Client object in the recievers list. This would be in the client read thread
if (sender.Type == ClientMode.Sender)
{
foreach (Client client in clients.Where(c => c.Type == ClientMode.Sender)
client.Send(message)
}
Obviously these are very broad strokes, and the full implementation would be far too large for SO. Hopefully that gets you on the right track, please let me know if I can clarify anything!
I have a client and server class in C# that uses socket communication. The Server looks like this:
public class AsyncTcpServer
{
private Socket _server_socket;
private Socket _client_socket;
private byte[] _receive_buffer;
private byte[] _send_buffer;
private NetworkStream _ns;
public void Start()
{
try
{
_server_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_server_socket.Bind(new IPEndPoint(IPAddress.Any, 17999));
_server_socket.Listen(0);
_server_socket.BeginAccept(new AsyncCallback(BeginAccept), null);
}
catch(Exception e)
{
Debug.Print(e.Message);
}
}
private void BeginAccept(IAsyncResult ar)
{
try
{
_client_socket = _server_socket.EndAccept(ar);
_receive_buffer = new byte[_client_socket.ReceiveBufferSize];
_send_buffer = new byte[_client_socket.ReceiveBufferSize];
_ns = new NetworkStream(_client_socket);
_client_socket.BeginReceive(_receive_buffer, 0, _receive_buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallback), null);
}
catch(Exception e)
{
Debug.Print(e.Message);
}
}
private void RecieveCallback(IAsyncResult ar)
{
try
{
string text = Encoding.ASCII.GetString(_receive_buffer);
Debug.Print("Server Received: " + text);
}
catch (Exception e)
{
Debug.Print("Unexpected exception: " + e.Message);
}
}
public void Send(byte [] bytes)
{
try
{
_ns.Write(bytes, 0, bytes.Length);
}
catch (Exception e)
{
Debug.Print("Unexpected exception: " + e.Message);
}
}
}
And the client looks like this:
public class AsyncTcpClient
{
private Socket _client_socket;
private byte[] _buffer;
private const int HEADER_SIZE = sizeof(int);
public void Start()
{
_client_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_client_socket.BeginConnect(new IPEndPoint(IPAddress.Loopback, 17999), new AsyncCallback(ConnectCallback), null);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
_client_socket.EndConnect(ar);
_buffer = new byte[_client_socket.ReceiveBufferSize];
StartReceive();
byte[] buffer = Encoding.ASCII.GetBytes("Connected!");
_client_socket.Send(buffer);
}
catch (Exception e)
{
Debug.Print(e.Message);
}
}
private void StartReceive(int offset = 0)
{
try
{
_client_socket.BeginReceive(_buffer, offset, _buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallback), null);
}
catch (Exception e)
{
Debug.Print(e.Message);
}
}
private void RecieveCallback(IAsyncResult ar)
{
try
{
int bytes_processed = 0;
int bytes_read = _client_socket.EndReceive(ar);
if (bytes_read > 0)
{
NetworkStream ns = new NetworkStream(_client_socket);
while (ns.DataAvailable && (bytes_processed < bytes_read))
{
byte[] len_bytes = new byte[HEADER_SIZE];
ns.Read(len_bytes, 0, HEADER_SIZE);
int current_chunk_size = BitConverter.ToInt32(len_bytes, 0);
if (current_chunk_size > 0)
{
byte[] data_buff = new byte[current_chunk_size];
ns.Read(data_buff, 0, current_chunk_size);
string s = Encoding.ASCII.GetString(data_buff);
bytes_processed += (HEADER_SIZE + current_chunk_size);
Debug.WriteLine(s);
}
}
}
StartReceive();
}
catch (Exception e)
{
Debug.Print(e.Message);
}
StartReceive();
}
}
They work together as follows:
Server starts
Client connects
Server sends custom packets to the client for its comsumption
I use the following 'data structure' to package my transmission data on the server side to send to the client:
{[DATA_LENGTH_IN_BYTES][PAYLOAD_BYTES]}
On the client side, I parse the first 4 bytes (sizeof(int)) to determine the payload length and then parse the payload itself. This works the first time I do it but after that the DataAvailable member of the NetworkStream is false and I can't parse the rest of the payload.
Why is DataAvailable false? I'm pretty new to doing this stuff in C# - am I approaching it the wrong way entirely?
Thanks in Advance!
Here is the solution I settled on:
Server:
public class Listener
{
private TcpListener _listener;
private TcpClient _client;
public void Start()
{
_listener = new TcpListener(IPAddress.Loopback, 17999);
_listener.Start();
_listener.BeginAcceptTcpClient(new AsyncCallback(AcceptTcpClientCallback), _listener);
}
private void AcceptTcpClientCallback(IAsyncResult ar)
{
try
{
Debug.WriteLine("Accepted tcp client callback");
_client = _listener.EndAcceptTcpClient(ar);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
public void Write(string data)
{
try
{
NetworkStream ns = _client.GetStream();
byte[] buffer = Encoding.ASCII.GetBytes(data);
ns.Write(buffer, 0, buffer.Length);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
}
And the client:
public class Client
{
private TcpClient _client;
private byte[] _buffer;
public void Start()
{
try
{
_client = new TcpClient();
_client.BeginConnect(IPAddress.Loopback, 17999, new AsyncCallback(ConnectCallback), _client);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
NetworkStream ns = _client.GetStream();
_buffer = new byte[_client.ReceiveBufferSize];
ns.BeginRead(_buffer, 0, _buffer.Length, new AsyncCallback(ReadCallback), null);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
private void ReadCallback(IAsyncResult ar)
{
try
{
NetworkStream ns = _client.GetStream();
int read = ns.EndRead(ar);
string data = Encoding.ASCII.GetString(_buffer, 0, read);
var res = data.Split(new [] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var r in res)
{
Debug.WriteLine(r); // process messages
}
ns.BeginRead(_buffer, 0, _buffer.Length, ReadCallback, _client);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
}
Where messages from the server to the client are formed as follows:
string message = "This is a message" + "\r\n";
_listener.Send(message);
I like this alternative for its simplicity. Its a lot shorter and (to me at least) much easier to manage.
HTH
I think you forget the EndReceive in the RecieveCallback. (server code)
private void RecieveCallback(IAsyncResult ar)
{
try
{
int bytesReceived = _client_socket.EndReceive(ar); // <---
string text = Encoding.ASCII.GetString(_receive_buffer);
Debug.Print("Server Received: " + text);
}
catch (Exception e)
{
Debug.Print("Unexpected exception: " + e.Message);
}
}
I advise to create one class that reads/writes to sockets (implementing the protocol). A Base class that handles reads/writes to Sockets, a client socket that is derived from the SocketConnection, but first will connect to an ipendpoint. A server that has a List of SocketConnection. This way you keep your client/server functionality separated of the message handling on socket. But both using the same code to receive/send messages. Here is an example:
Pseudo:
// base class that handle receive/sent packets
class SocketConnection
{
// the reason for a Start method is that event can be bound before the Start is executed.
void Start(Socket socket)
{
StartReceive();
}
void StartReceive()
{
socket.BeginReceive(...);
}
void EndReceive()
{
socket.EndReceive(...);
// handle received message.
// call the ondata event or something
StartReceive();
}
}
class ClientSocket : SocketConnection
{
void Connect()
{
Socket socket = new Socket(...);
socket.Connect(..);
// start receiving from the client socket.
base.Start(socket);
}
}
class Server
{
List<SocketConnection> _clients;
void Start()
{
// Create server socket + listening etc..
StartAccept();
}
void StartAccept()
{
serverSocket.BeginAccept(...);
}
void EndAccept()
{
Socket serverClientSocket = EndAccept(...);
// create a base socket handler.....
SocketConnection clientSocket = new SocketConnection();
_clients.Add(clientSocket);
// bind the ondata event of the client and pass it to the clientondata event of the server.
// Start receiving from the socket.
clientSocket.Start(serverClientSocket);
// accept new clients.
StartAccept();
}
}
UPDATE:
"Regarding how to handle buffers, what would you suggest as the best way to not miss data in separate packets?"
I would send a size first:
// sending part.
string message = "This is a message";
byte[] buffer = Encoding.ASCII.GetBytes(message);
_client_socket.Send(BitConverter.GetBytes(buffer.Length)); // sends a int as 4 bytes.
_client_socket.Send(data);
// receiving part.
// try to receive at least 4 bytes. (no more/ no less)
int length = BitConverter.ToInt32(buffer, 0);
// try to receive data with `length` size, (no more/ no less)
This will separate different packets.
Asynchronous example:
You still need to add some exception handling code.
public static class SocketReader
{
public static void ReadFromSocket(Socket socket, int count, Action<byte[]> endRead)
{
// read from socket, construct a new buffer.
DoReadFromSocket(socket, 0, count, new byte[count], endRead);
}
public static void ReadFromSocket(Socket socket, int count, ref byte[] buffer, Action<byte[]> endRead)
{
// if you do have a buffer available, you can pass that one. (this way you do not construct new buffers for receiving.
// the ref is because if the buffer is too small, it will return the newly created buffer.
// if the buffer is too small, create a new one.
if (buffer.Length < count)
buffer = new byte[count];
DoReadFromSocket(socket, 0, count, buffer, endRead);
}
// This method will continues read until count bytes are read. (or socket is closed)
private static void DoReadFromSocket(Socket socket, int bytesRead, int count, byte[] buffer, Action<byte[]> endRead)
{
// Start a BeginReceive.
socket.BeginReceive(buffer, bytesRead, count - bytesRead, SocketFlags.None, (result) =>
{
// Get the bytes read.
int read = socket.EndReceive(result);
// if zero bytes received, the socket isn't available anymore.
if (read == 0)
{
endRead(new byte[0]);
return;
}
// increase the bytesRead, (index point for the buffer)
bytesRead += read;
// if all bytes are read, call the endRead with the buffer.
if (bytesRead == count)
endRead(buffer);
else
// if not all bytes received, start another BeginReceive.
DoReadFromSocket(socket, bytesRead, count, buffer, endRead);
}, null);
}
}
Example how to use it:
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// read header. (length of data) (4 bytes)
SocketReader.ReadFromSocket(socket, 4, (headerBuffer) =>
{
if (headerBuffer.Length == 0)
{
// disconnected;
return;
}
int length = BitConverter.ToInt32(headerBuffer, 0);
// read bytes specified in length.
SocketReader.ReadFromSocket(socket, length, (dataBuffer) =>
{
if (dataBuffer.Length == 0)
{
// disconnected;
return;
}
// if you want this in a stream, you can do: This way the stream is readonly and only wraps arround the bytearray.
using (MemoryStream stream = new MemoryStream(dataBuffer, 0, length))
using (StreamReader reader = new StreamReader(stream))
while (!reader.EndOfStream)
Debug.WriteLine(reader.ReadLine());
});
});