I wrote client and server apps, there are those codes:
Client:
using System.Net.Sockets;
using System.Net;
using System.IO;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Client
{
class Program
{
private static TcpClient client = new TcpClient();
private static StreamReader reader;
private static StreamWriter writer;
private static bool refresh;
private static List<string> messages = new List<string>();
public static void Main()
{
Console.Title = "Client";
do //try to connect
{
Console.WriteLine("Connecting to server...");
try
{
client.Connect(IPAddress.Parse("127.0.0.1"), 8080);
}
catch (SocketException) { }
Thread.Sleep(10);
} while (!client.Connected);
// \/ CONNECTED \/
Console.WriteLine("Connected.");
reader = new StreamReader(client.GetStream());
writer = new StreamWriter(client.GetStream());
var sendTask = Task.Run(() => SendMessage()); //task for sending messages
var recieveTask = Task.Run(() => RecieveMessage()); //task for recieving messages
var updateConvTask = Task.Run(() => UpdateConversation()); //task for update console window
Task.WaitAll(sendTask, recieveTask); //wait for end of all tasks
}
private static void SendMessage()
{
string msgToSend = string.Empty;
do
{
Console.WriteLine("Enter a message to send to the server");
msgToSend = Console.ReadLine();
writer.WriteLine(msgToSend);
writer.Flush();
} while (!msgToSend.Equals("Exit"));
EndConnection();
}
private static void RecieveMessage()
{
try
{
while (client.Connected)
{
//Console.Clear();
string msg = reader.ReadLine();
if(msg != string.Empty)
{
if (msg == "%C") //special message from server, clear messages if recieve it
{
messages.Clear();
}
else
{
messages.Add(msg);
refresh = true; //refresh console window
}
}
//Console.Clear();
//Console.WriteLine(msgFromServer);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static void UpdateConversation()
{
//string conversationTmp = string.Empty;
try
{
while (true)
{
if (refresh) //only if refresh
{
refresh = false;
Console.Clear();
messages.ForEach(msg => Console.WriteLine(msg)); //write all messages
Console.WriteLine();
}
}
}
catch (Exception) { }
}
private static void EndConnection()
{
reader.Close();
writer.Close();
client.Close();
}
}
}
Server:
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Server
{
class Program
{
private static List<Client> clients = new List<Client>();
private static TcpListener listener = null;
private static StreamReader reader = null;
private static StreamWriter writer = null;
private static List<Task> clientTasks = new List<Task>();
private static List<string> messages = new List<string>();
public static void Main()
{
Console.Title = "Server";
try
{
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8080);
listener.Start();
Console.WriteLine("Server started...");
var connectTask = Task.Run(() => ConnectClients());
//var listenTask = Task.Run(() => ListenClients());
Task.WaitAll(connectTask);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
if (listener != null)
{
listener.Stop();
}
}
}
private static void ConnectClients()
{
Console.WriteLine("Waiting for incoming client connections...");
while (true)
{
if (listener.Pending()) //if someone want to connect
{
clients.Add(new Client(listener.AcceptTcpClient(), "Client: " + (clients.Count + 1)));
Console.WriteLine(clients[clients.Count - 1].clientName + " connected to server.");
clientTasks.Add(Task.Run(() => HandleClient(clients[clients.Count - 1]))); //start new task for new client
}
}
}
private static void HandleClient(Client TCPClient)
{
string s = string.Empty;
writer = new StreamWriter(TCPClient.client.GetStream());
reader = new StreamReader(TCPClient.client.GetStream());
try
{
while (!(s = reader.ReadLine()).Equals("Exit") || (s == null))
{
if(!TCPClient.client.Connected)
{
Console.WriteLine("Client disconnected.");
clients.Remove(TCPClient);
}
Console.WriteLine("From client: " + TCPClient.clientName + " -> " + s);
messages.Add(TCPClient.clientName + ": " + s); //save new message
//Console.WriteLine(s);
foreach (Client c in clients) //refresh all connected clients
{
c.writer.WriteLine("%C"); //clear client
foreach (string msg in messages)
{
c.writer.WriteLine(msg);
c.writer.Flush();
}
}
}
CloseServer();
}
catch (Exception e) { Console.WriteLine(e); }
}
private static void CloseServer()
{
reader.Close();
writer.Close();
clients.ForEach(tcpClient => tcpClient.client.Close());
}
}
}
Client class code:
class Client
{
public TcpClient client;
public StreamWriter writer; //write to client
public string clientName;
public Client(TcpClient client, string clientName)
{
this.client = client;
reader = new StreamReader(client.GetStream());
writer = new StreamWriter(client.GetStream());
this.clientName = clientName;
}
}
Clients send messages to the server that store all of them and next send back the entire conversation to all clients.
Client class contains information about the connected client, a server has a list of Client instances.
For one client it works well, but when I have two clients, in begin it works too, but after a few messages one client send messages to them two, and another client can't send messages.
Please help, I'm new in TCP communication.
I think that you would synchronize Tasks: https://www.google.pl/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=synchronizing+tasks+c%23
Related
See the problem in the picture. The Server starts a new Task for accepting the clients and then handles it in the function Handle(client), this all works fine, but it every time it repeats this one message "Client connecting...", but it shouldn't. Nothing else of the Task is called but this message. And the bool Pending() is false, so it shouldn't start another Task.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WebServer
{
class WebServer
{
public static WebServer Server { get; private set; }
private TcpListener _tcpListener = null;
public CancellationTokenSource TokenSource { get; private set; }
public CancellationToken Token { get; private set; }
public int i = 0;
static void Main(string[] args)
{
WebServer.Server = new WebServer();
}
WebServer()
{
IPAddress ipAddress;
try
{
ipAddress = IPAddress.Parse("127.0.0.1");
} catch(Exception e)
{
Console.WriteLine("Error while parsing ip address: " + e.Message);
return;
}
_tcpListener = new TcpListener(ipAddress, 8080);
_tcpListener.Start();
TokenSource = new CancellationTokenSource();
Token = TokenSource.Token;
//Execute server
Task.Run(() => Run());
Console.ReadKey();
TokenSource.Cancel();
WaitHandle handle = Token.WaitHandle;
handle.WaitOne();
}
private void Run()
{
Console.WriteLine("Server is runnning");
while(!Token.IsCancellationRequested)
{
if(_tcpListener.Pending())
{
Console.WriteLine("Pending: " + _tcpListener.Pending());
Task.Run(() => {
Console.WriteLine("Client connecting...");
TcpClient client = _tcpListener.AcceptTcpClient();
this.Handle(client);
return;
});
}
}
}
private void Handle(TcpClient client)
{
NetworkStream stream = client.GetStream();
Console.WriteLine("Handling....");
while(client.Connected)
{
if(stream.DataAvailable)
{
Console.WriteLine("Start Reading...");
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, 1024);
Console.WriteLine("Read: " + Encoding.ASCII.GetString(buffer));
}
client.Close();
}
}
}
}
Client connecting shouldn't repeat every time, everything else works
Emrah Süngü's comments seem accurate and correct
TcpClient client = _tcpListener.AcceptTcpClient(); // accept first
Console.WriteLine("Client connecting...");
// then start processing in your task
Task.Run(() => this.Handle(client));
It makes perfect sense when you think about it, you are in a while loop, and you are starting several tasks before the code to except the client actually runs.
Disclaimer : This is totally untested and i am not responsible for and harm you cause to others or your self with this code :)
Yesterday I started a project where you can chat with people in a specific chat room in a C# Console Application. There is a TCPListener on the server-side that continuously listens for incoming connections and handles each incoming connection on a separate thread. On the client-side you can connect to this listener by entering an IP address and nickname and you are connected to the TCPListener.
I am able to send messages from Client => Server and the messages arrive at the server, but when multiple clients are connected the other clients won't see my message.
For instance, I have two clients connected to the listener: one with nickname 'user1' and one with nickname 'user2'. When user1 sends a message, the server receives it. When user2 sends a message, the server receives it too. But user1 does not see what user2 sent to the server and vice-versa.
My question
My question is:
How can I make TCPClients connected to the TCPListener receive the messages from other TCPClients?
Additional information
I've added some comments to make it easy to understand the methods I used. The listener listens on port 8345.
Client
public static void Connect(string serverIP, string nickname)
{
try
{
TcpClient client = new TcpClient();
NetworkStream stream = null;
MessageHelper helper = null;
client.Connect(serverIP, PORT);
stream = client.GetStream();
helper = new MessageHelper(client, stream);
helper.SendMessage($"!nickname={nickname}");
Log("Connected!");
Thread receiveThread = new Thread(new ThreadStart(() =>
{
while (true)
{
// Get messages from other senders
helper.ReadMessage();
Thread.Sleep(300);
}
}));
receiveThread.Start();
while (Util.IsClientConnected(client))
{
Console.Write(" > ");
var message = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(message))
{
try
{
helper.SendMessage(message);
}
catch (IOException)
{
Log("The server closed unexpectedly.");
}
}
}
Log("Disconnected.");
}
catch (SocketException ex)
{
Log("SocketException: " + ex.ToString());
}
}
Server
public static bool IsListening;
private const int PORT = 8345;
public static void HandleClient(object _client)
{
TcpClient client = (TcpClient)_client;
NetworkStream stream = null;
MessageHelper helper = null;
var ipAddress = MessageHelper.GetIpInformation(client).IpAddress.ToString();
stream = client.GetStream();
helper = new MessageHelper(client, stream);
// Initial read, assuming this will be a '!nickname' command it will set the nickname
helper.ReadMessage();
Log($"{helper.Nickname} ({ipAddress}) connected.");
while (Util.IsClientConnected(client))
{
try
{
// Check every 300 ms for a new message and print it to the screen.
helper.ReadMessage();
}
catch (IOException)
{
Log($"{helper.Nickname} disconnected.");
}
Thread.Sleep(300);
}
}
public static void StartListener()
{
TcpListener listener = null;
IPAddress ipAddress = IPAddress.Any;
listener = new TcpListener(ipAddress, PORT);
try
{
listener.Start();
IsListening = true;
Log($"Listener started at {ipAddress}:{PORT}.");
}
catch (Exception ex)
{
Log("Error: " + ex.ToString());
}
while (IsListening)
{
// Check if listener is handling a pending connection, if not, wait 250 ms.
if (!listener.Pending())
{
Thread.Sleep(250);
continue;
}
// Client connected, handle at a separate thread.
TcpClient client = listener.AcceptTcpClient();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient));
clientThread.Start(client);
}
}
MessageHelper.cs
public class MessageHelper
{
public string Nickname { get; set; }
public TcpClient Client { get; set; }
public NetworkStream Stream { get; set; }
public MessageHelper(TcpClient client, NetworkStream stream)
{
Client = client;
Stream = stream;
}
public static IpInformation GetIpInformation(TcpClient client, bool isRemote = true)
{
string fullHostname;
if (isRemote)
fullHostname = client.Client.RemoteEndPoint.ToString();
else
fullHostname = client.Client.LocalEndPoint.ToString();
IpInformation info = new IpInformation()
{
IpAddress = IPAddress.Parse(fullHostname.Split(':')[0]),
Port = int.Parse(fullHostname.Split(':')[1])
};
return info;
}
public string GetMessageFormat(string message)
{
DateTime dateTime = DateTime.Now;
return $" [{dateTime.ToShortTimeString()}] <{Nickname}>: {message}";
}
public void ReadMessage()
{
byte[] data = new byte[256];
int byteCount = Stream.Read(data, 0, data.Length);
string ipAddress = GetIpInformation(Client).IpAddress.ToString();
string message = Encoding.ASCII.GetString(data, 0, byteCount);
// Check if message is a command
if (message.StartsWith("!"))
{
try
{
// Command format is >> !command=value <<
string[] commandSplit = message.TrimStart('!').Split('=');
string command = commandSplit[0];
string value = commandSplit[1];
if (command == "nickname")
{
Nickname = value;
}
else
{
Log("This command is not found.");
}
}
catch (Exception)
{
}
}
else
{
// Regular message, print it to the console window.
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine(GetMessageFormat(message));
Console.ResetColor();
}
}
public void SendMessage(string message)
{
byte[] data = Encoding.ASCII.GetBytes(message);
Stream.Write(data, 0, data.Length);
if (!message.StartsWith("!"))
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(GetMessageFormat(message));
Console.ResetColor();
}
else
{
// Issue the '!nickname' command
if (message.StartsWith("!nickname"))
{
try
{
Nickname = message.TrimStart('!').Split('=')[1];
}
catch (IndexOutOfRangeException)
{
Log("Please enter an argument for this command.");
}
}
}
}
}
In the MessageHelper.cs class ReadMessage method you are not storing the messages or you are not broadcasting the messages to all the clients.
To broadcast
Create an Event in MessageHelper and raise the event at
Console.WriteLine(GetMessageFormat(message)); .
Pass the message in
EventHandler in the Event.
In Client.cs file, Handle the event to recieve all the messages
Sample Code
In MessageHelper Class declare event as
public event EventHandler ReadMessageEvent;
In ReadMessage Method at Console.WriteLine(GetMessageFormat(message)); replace with
if (ReadMessageEvent!= null)
ReadMessageEvent.Invoke(GetMessageFormat(message), null);
In Client class try block add below code
helper.ReadMessageEvent += ReadMessageEvent_HandleEvent;
private void ReadMessageEvent_HandleEvent(object sender, EventArgs e)
{
string message = sender as string;
Console.WriteLine(message);
}
Somehow I am not able to get named pipes work for duplex communication between client and server for .Net app.
Duplex communication works fine when I go for sequential messaging, but when I make it random i.e., server and client can ping each other at any random time, it just doesn't work.
The other posts are not much helpful either - c# Full Duplex Asynchronous Named Pipes .NET
I am attaching my code as below:
-Server code:
namespace Server
{
class Program
{
static void Main(string[] args)
{
var namedPipeServerStream = new NamedPipeServerStream("myPipe",
PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
Task.Run(() => StartListeningAsync(namedPipeServerStream, (msg) => Console.WriteLine(msg)));
Task.Run(() => SendMessageAsync(namedPipeServerStream));
Console.ReadLine();
}
public static async Task SendMessageAsync(NamedPipeServerStream namedPipeServer)
{
using (var stream = new StreamWriter(namedPipeServer))
{
while (true)
{
await Task.Delay(2000);
try
{
var serialized = JsonConvert.SerializeObject($"Server {DateTime.Now}");
byte[] messageBytes = Encoding.UTF8.GetBytes(serialized);
if (!namedPipeServer.IsConnected)
{
namedPipeServer.WaitForConnection();
Console.WriteLine("Client connected");
}
await namedPipeServer.WriteAsync(messageBytes, 0, messageBytes.Length);
await namedPipeServer.FlushAsync();
namedPipeServer.WaitForPipeDrain();
}
catch (Exception exception)
{
Console.WriteLine($"Exception:{exception}");
}
}
}
}
public static async Task StartListeningAsync(NamedPipeServerStream namedPipeServer, Action<string> messageRecieved)
{
while (true)
{
try
{
StringBuilder messageBuilder = new StringBuilder();
string messageChunk = string.Empty;
byte[] messageBuffer = new byte[1024];
do
{
if (!namedPipeServer.IsConnected)
{
namedPipeServer.WaitForConnection();
Console.WriteLine("Client connected");
}
await namedPipeServer.ReadAsync(messageBuffer, 0, messageBuffer.Length);
messageChunk = Encoding.UTF8.GetString(messageBuffer);
messageBuilder.Append(messageChunk);
messageBuffer = new byte[messageBuffer.Length];
} while (!namedPipeServer.IsMessageComplete);
if (messageRecieved != null)
{
messageRecieved(JsonConvert.DeserializeObject<string>(messageBuilder.ToString()));
}
}
catch (Exception exception)
{
Console.WriteLine($"Exception:{exception}");
}
}
}
}
}
Client code:
namespace Client
{
class Program
{
static void Main(string[] args)
{
var namedPipeClientStream = new NamedPipeClientStream(".", "server", PipeDirection.InOut, PipeOptions.Asynchronous,
TokenImpersonationLevel.Impersonation);
Task.Run(() => StartListeningAsync(namedPipeClientStream, (msg) => Console.WriteLine(msg)));
Task.Run(() => SendMessageAsync(namedPipeClientStream));
Console.ReadLine();
}
public static async Task SendMessageAsync(NamedPipeClientStream namedPipeClient)
{
using (var stream = new StreamWriter(namedPipeClient))
{
while (true)
{
try
{
await Task.Delay(3000);
var serialized = JsonConvert.SerializeObject($"Client {DateTime.Now}");
byte[] messageBytes = Encoding.UTF8.GetBytes(serialized);
if (!namedPipeClient.IsConnected)
{
namedPipeClient.Connect();
namedPipeClient.ReadMode = PipeTransmissionMode.Message;
Console.WriteLine("Client connected");
}
await namedPipeClient.WriteAsync(messageBytes, 0, messageBytes.Length);
await namedPipeClient.FlushAsync();
namedPipeClient.WaitForPipeDrain();
}
catch (Exception exception)
{
Console.WriteLine($"Exception:{exception}");
}
}
}
}
public static async Task StartListeningAsync(NamedPipeClientStream namedPipeClient, Action<string> messageRecieved)
{
using (var streamReader = new StreamReader(namedPipeClient))
{
while (true)
{
try
{
StringBuilder messageBuilder = new StringBuilder();
string messageChunk = string.Empty;
byte[] messageBuffer = new byte[1024];
do
{
if (!namedPipeClient.IsConnected)
{
namedPipeClient.Connect();
namedPipeClient.ReadMode = PipeTransmissionMode.Message;
}
await namedPipeClient.ReadAsync(messageBuffer, 0, messageBuffer.Length);
messageChunk = Encoding.UTF8.GetString(messageBuffer);
messageBuilder.Append(messageChunk);
messageBuffer = new byte[messageBuffer.Length];
} while (!namedPipeClient.IsMessageComplete);
if (messageRecieved != null)
{
messageRecieved(JsonConvert.DeserializeObject<string>(messageBuilder.ToString()));
}
}
catch (Exception exception)
{
Console.WriteLine($"Exception:{exception}");
}
}
}
}
}
}
I created a tcp server and a tcp client. I tried to run the client async but had some problems.
Now when I call the function with await ReceiveAsync(id) the whole program gets blocked. I have to start the function in a new task Task.Run(() => ReceiveAsync()), then it works fine.
Now, I thought when I use the async version of readlineasync I can call the function with await ReceiveAsync() and everything works without blocking. How can I implement the function correct to receive continuous data from the server, without blocking the program and without creating a new task?
Server
main.cs
namespace Server
{
class Program
{
static void Main(string[] args)
{
// Start the server
TcpHelper.StartServer(5678);
TcpHelper.Listen(); // Start listening.
}
}
}
TcpHelper.cs
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Server
{
public class TcpHelper
{
private static TcpListener listener { get; set; }
private static bool accept { get; set; } = false;
public static void StartServer(int port)
{
IPAddress address = IPAddress.Parse("127.0.0.1");
listener = new TcpListener(address, port);
listener.Start();
accept = true;
Console.WriteLine($"Server started. Listening to TCP clients at 127.0.0.1:{port}");
}
public static void Listen()
{
if (listener != null && accept)
{
// Continue listening.
while (true)
{
Console.WriteLine("Waiting for client...");
var clientTask = listener.AcceptTcpClientAsync(); // Get the client
if (clientTask.Result != null)
{
Console.WriteLine("Client connected. Waiting for data.");
var client = clientTask.Result;
string message = "";
while (message != null && !message.StartsWith("quit"))
{
//for (int i = 0; i < 100; i++)
//{
// byte[] data = Encoding.ASCII.GetBytes("Send next data: [enter 'quit' to terminate] ");
// client.GetStream().Write(data, 0, data.Length);
// Thread.Sleep(4000);
//}
byte[] data = Encoding.ASCII.GetBytes("Send next data: [enter 'quit' to terminate] \n");
client.GetStream().Write(data, 0, data.Length);
byte[] buffer = new byte[1024];
client.GetStream().Read(buffer, 0, buffer.Length);
message = Encoding.ASCII.GetString(buffer);
Console.WriteLine(message);
}
Console.WriteLine("Closing connection.");
client.GetStream().Dispose();
}
}
}
}
}
}
Client
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace TestTcpSocket
{
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
TcpClient client = Connect(IPAddress.Parse("127.0.0.1"), 5678).Result;
//await ReceiveAsync(client); // Blocks the whole program
Task.Run(() => ReceiveAsync(client)); // Works
string line;
while ((line = Console.ReadLine()) != null)
{
await SendAsync(client, line);
}
}
private static async Task<TcpClient> Connect(IPAddress address, int port)
{
TcpClient client = new TcpClient();
await client.ConnectAsync(address, port);
return client;
}
private static async Task SendAsync(TcpClient client, string message)
{
NetworkStream networkStream = client.GetStream();
StreamWriter writer = new StreamWriter(networkStream);
StreamReader reader = new StreamReader(networkStream);
writer.AutoFlush = true;
await writer.WriteLineAsync(message);
}
private static async Task ReceiveAsync(TcpClient client)
{
NetworkStream networkStream = client.GetStream();
StreamWriter writer = new StreamWriter(networkStream);
StreamReader reader = new StreamReader(networkStream);
writer.AutoFlush = true;
while (true)
{
string response = await reader.ReadLineAsync();
}
}
}
}
I have written this code for my server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
private static bool terminate;
public static bool Terminate
{
get { return terminate; }
}
private static int clientNumber = 0;
private static TcpListener tcpListener;
static void Main(string[] args)
{
StartServer();
Console.Read();
}
private static void StartServer()
{
try
{
Console.WriteLine("Server starting...");
tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8000);
terminate = false;
tcpListener.Start();
tcpListener.BeginAcceptTcpClient(ConnectionHandler, null);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine("Server stopping...");
terminate = true;
if (tcpListener != null)
{
tcpListener.Stop();
}
}
}
private static void ConnectionHandler(IAsyncResult result)
{
TcpClient client = null;
try
{
client = tcpListener.EndAcceptTcpClient(result);
}
catch (Exception)
{
return;
}
tcpListener.BeginAcceptTcpClient(ConnectionHandler, null);
if (client!=null)
{
Interlocked.Increment(ref clientNumber);
string clientName = clientNumber.ToString();
new ClientHandler(client, clientName);
}
}
}
}
class ClientHandler
{
private TcpClient client;
private string ID;
internal ClientHandler(TcpClient client, string ID)
{
this.client = client;
this.ID = ID;
Thread thread = new Thread(ProcessConnection);
thread.IsBackground = true;
thread.Start();
}
private void ProcessConnection()
{
using (client)
{
using (BinaryReader reader=new BinaryReader(client.GetStream()))
{
if (reader.ReadString()==Responses.RequestConnect)
{
using (BinaryWriter writer=new BinaryWriter(client.GetStream()))
{
writer.Write(Responses.AcknowledgeOK);
Console.WriteLine("Client: "+ID);
string message = string.Empty;
while (message!=Responses.Disconnect)
{
try
{
message = reader.ReadString();
}
catch
{
continue;
}
if (message==Responses.RequestData)
{
writer.Write("Data Command Received");
}
else if (message==Responses.Disconnect)
{
Console.WriteLine("Client disconnected: "+ID);
}
else
{
Console.WriteLine("Unknown Command");
}
}
}
}
else
{
Console.WriteLine("Unable to connect client: "+ID);
}
}
}
}
}
class Responses
{
public const string AcknowledgeOK = "OK";
public const string AcknowledgeCancel = "Cancel";
public const string Disconnect = "Bye";
public const string RequestConnect = "Hello";
public const string RequestData = "Data";
}
this code listen for client requests in a multi threaded way. I am unable to understand how can i distinguish between different clients connected to my this server and which client is disconnecting and requesting for different commands.
my client code is:
private static void clietnRequest(string message,ref string response)
{
using (TcpClient client = new TcpClient())
{
if (!client.Connected)
{
client.Connect(IPAddress.Parse("127.0.0.1"), 8000);
using (NetworkStream networkStream = client.GetStream())
{
using (BinaryWriter writer = new BinaryWriter(networkStream))
{
writer.Write(Responses.RequestConnect);
using (BinaryReader reader = new BinaryReader(networkStream))
{
if (reader.ReadString() == Responses.AcknowledgeOK)
{
response = Responses.AcknowledgeOK;
}
}
}
}
}
}
}
this piece of code connects the client to server, but i am unable to send anymore messages. I want in my app if client is connected then he can send commands to server. instead of doing this it every time act as a new client to server. I am missing some thing here, Kindly guide me in right direction. I am totally new to c# networking programming. Kindly help me improve my code. Tcp Listener and Tcp Client is valid for this scenario or do I need to use Sockets?
You are closing the connection every time client side after you send a message, if you want to do that there is nothing wrong with it but you will need to send some form of identification to the server so it can tell that this is not a new connection but a old connection connecting in for a second time. This is EXACTLY what the HTTP protocol is doing and that "identification" are internet cookies.
That first option is fine if you transmit data very infrequently but if you are doing it more often you need to keep the connection open.
Basicly you need to take the act of connecting and disconnecting out of the client request function and pass the open connection in as a argument.
private void MainCode()
{
using (TcpClient client = new TcpClient())
{
client.Connect(IPAddress.Parse("127.0.0.1"), 8000);
while(variableThatRepresentsRunning)
{
//(Snip logic that gererates the message)
clietnRequest(message, ref response, client);
//(Snip more logic)
}
}
}
private static void clietnRequest(string message,ref string response, TcpClient client)
{
if (client.Connected)
{
using (NetworkStream networkStream = client.GetStream())
{
using (BinaryWriter writer = new BinaryWriter(networkStream))
{
writer.Write(Responses.RequestConnect);
using (BinaryReader reader = new BinaryReader(networkStream))
{
if (reader.ReadString() == Responses.AcknowledgeOK)
{
response = Responses.AcknowledgeOK;
}
}
}
}
}
else
{
//Show some error because the client was not connected
}
}
By doing it this way the client object server side represents the client, you will have one instance of it per connected client and will remain associated with that client till he disconnects. If you want to track all of the connected clients you will need to insert them all in to some collection like a List<TcpClient> (either use a Concurrent Collection or use locking because you are multi-threaded) and then you will have a list of all clients (you will need to have the clients clean up after themselves so they remove themselves from the list after a disconnection).