I am working on multi thread server and clients written in C#.So Guide
me how can I make multi thread in server for multi client.
This is my Server Code
class Program
{
static byte[] Buffer
{
get;
set;
}
static void Main(string[] args)
{
Program obj = new Program();
Console.WriteLine("Server");
obj.server_reciver();
}
static Socket sck;
public void server_reciver()
{
try
{
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndPoint;
localEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.2"), 1);
sck.Bind(localEndPoint);
sck.Listen(100);
while (true)
{
Socket accepted = sck.Accept();
// Buffer = new byte[accepted.ReceiveBufferSize];
Buffer = new byte[accepted.SendBufferSize];
int bytesRead = accepted.Receive(Buffer);
byte[] formatted = new byte[bytesRead];
//for (int i = 0; i < bytesRead; i++)
for (int i = 0; i < bytesRead; i++)
{
formatted[i] = Buffer[i];
//Console.WriteLine(Buffer[i] + "\r\n");
}
//string strData = Encoding.ASCII.GetString(Buffer);
string strData = Encoding.ASCII.GetString(formatted);
Console.Write("From Client=>" + strData + "\n");
Console.WriteLine("Enter the text:");
string data = Console.ReadLine();
byte[] reply = Encoding.ASCII.GetBytes(data);
accepted.Send(reply);
//accepted.Close();
accepted.Close();
}
sck.Close();
Console.Read();
}
catch (Exception ex)
{
}
}
}
This is my Client side and I make more then one client here is one
class Program
{
static byte[] Buffer
{
get;
set;
}
static Socket sck;
static void Main(string[] args)
{
Program obj = new Program();
obj.client_send();
}
public void client_send()
{
while (true)
{
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndPoint;
localEndPoint = new IPEndPoint(IPAddress.Parse("182.188.247.244"), 1);
//localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.45"), 1);
try
{
sck.Connect(localEndPoint);
}
catch
{
Console.Write("Unable to connect to remote end point!\r\n");
//Main(args);
}
try
{
Console.Write("Enter Text: ");
string text = Console.ReadLine();
byte[] data = Encoding.ASCII.GetBytes(text);
sck.Send(data);
Buffer = new byte[sck.SendBufferSize];
int bytesRead = sck.Receive(Buffer);
byte[] formatted = new byte[bytesRead];
for (int i = 0; i < bytesRead; i++)
{
formatted[i] = Buffer[i];
//Console.WriteLine(Buffer[i] + "\r\n");
}
string strData = Encoding.ASCII.GetString(formatted);
Console.Write("From Server=>" + strData + "\n");
sck.Close();
}
catch(Exception )
{
}
}
Console.ReadLine();
}
}
Typically, you would keep Socket accepted = sck.Accept(); on the main thread, but once a request is received you would pass it to another thread for servicing. This allows the main thread to listed to another incoming request. You can use ThreadPool.QueueUserWorkItem to move the work to a background thread. Note that making it multi-threaded is going to give you problems since the response is read from Console. How is each worker thread to know that it gets the right data? But I assume you'll replace that with real server logic.
At some point, you may find that this doesn't scale. You're using blocking IO calls (Send and Receive) so your threads will spend a lot of time waiting. Non-blocking IO would be ideal, but it is more complicated to write.
Related
At the fist try, I created a basic TCP server as flowing:
public class Tcp
{
private TcpListener listener { get; set; }
private bool accept { get; set; } = false;
public void StartServer(string ip, int port)
{
IPAddress address = IPAddress.Parse(ip);
listener = new TcpListener(address, port);
listener.Start();
accept = true;
StartListener();
Console.WriteLine($"Server started. Listening to TCP clients at {ip}:{port}");
}
public async void StartListener() //non blocking listener
{
listener.Start();
while (true)
{
try
{
TcpClient client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
HandleClient(client);
}
finally { }
}
}
private void HandleClient(TcpClient client)
{
try
{
NetworkStream networkStream = client.GetStream();
byte[] bytesFrom = new byte[20];
networkStream.Read(bytesFrom, 0, 20);
string dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
string serverResponse = "Received!";
Byte[] sendBytes = Encoding.ASCII.GetBytes(serverResponse);
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
}
catch(Exception ex)
{
}
}
}
I wrote a client test code that is sending and recording number of requests per second
public class Program
{
private volatile static Dictionary<int, int> connections = new Dictionary<int, int>();
private volatile static int fail = 0;
private static string message = "";
public static void Main(string[] args)
{
ServicePointManager.DefaultConnectionLimit = 1000000;
ServicePointManager.Expect100Continue = false;
for (int i = 0; i < 512; i++)
{
message += "T";
}
int taskCount = 10;
int requestsCount = 1000;
var taskList = new List<Task>();
int seconds = 0;
Console.WriteLine($"start : {DateTime.Now.ToString("mm:ss")} ");
for (int i = 0; i < taskCount; i++)
{
taskList.Add(Task.Factory.StartNew(() =>
{
for (int j = 0; j < requestsCount; j++)
{
Send();
}
}));
}
Console.WriteLine($"threads stablished : {DateTime.Now.ToString("mm: ss")}");
while (taskList.Any(t => !t.IsCompleted)) { Thread.Sleep(5000); }
Console.WriteLine($"Compelete : {DateTime.Now.ToString("mm: ss")}");
int total = 0;
foreach (KeyValuePair<int, int> keyValuePair in connections)
{
Console.WriteLine($"{keyValuePair.Key}:{keyValuePair.Value}");
total += keyValuePair.Value;
seconds++;
}
Console.WriteLine($"succeded:{total}\tfail:{fail}\tseconds:{seconds}");
Console.WriteLine($"End : {DateTime.Now.ToString("mm: ss")}");
Console.ReadKey();
}
private static void Send()
{
try
{
TcpClient tcpclnt = new TcpClient();
tcpclnt.ConnectAsync("192.168.1.21", 5678).Wait();
String str = message;
Stream stm = tcpclnt.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(str);
stm.Write(ba, 0, ba.Length);
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
tcpclnt.Close();
lock (connections)
{
int key = int.Parse(DateTime.Now.ToString("hhmmss"));
if (!connections.ContainsKey(key))
{
connections.Add(key, 0);
}
connections[key] = connections[key] + 1;
}
}
catch (Exception e)
{
lock (connections)
{
fail += 1;
}
}
}
}
when I test it on a local machine, I get the maximum number of 4000 requests per second and when I upload it to local Lan it decreases to 200 requests per second.
The question is:
how can I improve the server performance?
what is the correct way of load testing socket servers?
You may have a "non-blocking listener", but when any particular client connects, it devotes itself to just that client until that client has sent a message and a response has been sent back to it. That's not going to scale well.
I'm usually not a fan of async void, but it's in keeping with your current code:
public async void StartListener() //non blocking listener
{
listener.Start();
while (true)
{
TcpClient client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
HandleClient(client);
}
}
private async void HandleClient(TcpClient client)
{
NetworkStream networkStream = client.GetStream();
byte[] bytesFrom = new byte[20];
int totalRead = 0;
while(totalRead<20)
{
totalRead += await networkStream.ReadAsync(bytesFrom, totalRead, 20-totalRead).ConfigureAwait(false);
}
string dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
string serverResponse = "Received!";
Byte[] sendBytes = Encoding.ASCII.GetBytes(serverResponse);
await networkStream.WriteAsync(sendBytes, 0, sendBytes.Length).ConfigureAwait(false);
networkStream.Flush(); /* Not sure necessary */
}
I've also fixed the bug I mentioned in the comments about ignoring the return value from Read and removed the "hide errors from me making bugs impossible to spot in the wild" error handling.
If you're not guaranteed that your clients will always send a 20 byte message to this code, then you need to do something else so that the server knows how much data to read. This is usually done by either prefixing the message with its length or using some form of sentinel value to indicate the end. Note that even with length-prefixing, you're not guaranteed to read the whole length in one go and so you'd need to also use a read loop, as above, to discover the length first.
If switching everything to async isn't giving you the scale you need, then you need to abandon using NetworkStream and start working at the Socket level, and specifically with the async methods designed to work with SocketAsyncEventArgs:
The SocketAsyncEventArgs class is part of a set of enhancements to the System.Net.Sockets.Socket class that provide an alternative asynchronous pattern that can be used by specialized high-performance socket applications... An application can use the enhanced asynchronous pattern exclusively or only in targeted hot areas (for example, when receiving large amounts of data).
The main feature of these enhancements is the avoidance of the repeated allocation and synchronization of objects during high-volume asynchronous socket I/O...
In the new System.Net.Sockets.Socket class enhancements, asynchronous socket operations are described by reusable SocketAsyncEventArgs objects allocated and maintained by the application...
my software consists of two parts. one of them is client, i can connect my device on router via ethernet and i can send a command ( data ) then i am starting to wait getting response from my device, but i cannot figure out how i could get responce, despite of the fact that i have been looking for similar socket application. i have studying c# for 2 weeks. Would you help me about this topic ?
If you can help me, i will be really pleasure you.
namespace sencron_socket
{
class Program
{
static Socket sck;
static Socket scks;
static byte[] Buffer { get; set; }
static void Main(string[] args)
{
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localendpoint = new IPEndPoint(IPAddress.Parse("172.16.204.101"), 50007); //50007 bidirectional interface The event
try
{
sck.Connect(localendpoint);
if (sck.Poll(-1, SelectMode.SelectWrite))
{
Console.WriteLine("this socket is writable");
}
else if (sck.Poll(-1, SelectMode.SelectError))
{
Console.WriteLine("this socket has an error");
}
}
catch
{
Console.Write(" unable ");
Main(args);
}
Console.Write("enter text: ");
string text = Console.ReadLine();
byte[] data = Encoding.ASCII.GetBytes(text);
sck.Send(data);
Console.Write(" data sent! \r\n ");
//Console.Write(" press ant key to continue ");
// Console.Read();
sck.Close();
scks = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
scks.Bind(new IPEndPoint(IPAddress.Parse("172.16.204.104"),0));
scks.Listen(1);
Console.Write(" it is ok until this step ");
// ???????????????????????????????????????????????????????
// i think that my problem starts next line with Accept()
Socket accepted = scks.Accept();
Console.Write(" BURDA 222 \r\n");
IPEndPoint remoteEndPoint = (IPEndPoint)accepted.RemoteEndPoint;
Buffer = new byte[accepted.SendBufferSize];
int bytesRead = accepted.Receive(Buffer);
byte[] formatted = new byte[bytesRead];
/* for (int i = 0; i < bytesRead; i++)
{
formatted[i] = Buffer[i];
}*/
Console.Write(" BURDA 3333 ");
string strData = Encoding.ASCII.GetString(formatted);
Console.Write(strData + "\r\n");
scks.Close();
accepted.Close();
Console.Read();
}
}
}
Good afternoon, i've been trying to make a system kinda like skype in terms of convo groups, being able to enter a group and chatting with others that were online only within that group, issue is i dont know how i could separate this chat room into several ones and making them independent from each other with just one server
Overall, im trying to have multi chat rooms with one server while being able to save one's conversation chat log and be able to read it back
The current code i have works only as 1 general chat room
Server Side:
static void Main(string[] args)
{
Socket newSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Ip);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 6000);
newSocket.Bind(endPoint);
newSocket.Listen(10);
Console.Write("Waiting...\n");
while (true)
{
Socket auxSocket = newSocket.Accept();
ThreadLab a = new ThreadLab(auxSocket);
Thread novaThread = new Thread(new ThreadStart(a.Connect));
novaThread.Start();
}
}
The ThreadLab Class:
private Socket socket;
static int nmrUsers = 0;
static int indice;
static Socket[] listaSockets = new Socket[10];
static ArrayList listaUtilizadores = new ArrayList();
public ThreadLab(Socket s)
{
socket = s;
listaSockets[indice++] = s;
}
public void Connect()
{
IPEndPoint aux = (IPEndPoint)socket.RemoteEndPoint;
Console.Write("Client " + aux.Address.ToString() + " connected\n");
}
And the client side that will have the reader and writer:
private static Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Ip);
private static ThreadStart tSReader;
private static ThreadStart tSWriter;
private static Thread tReader;
private static Thread tWriter;
private static string nome;
static void Main(string[] args)
{
IPEndPoint clientEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6000);
tSReader = new ThreadStart(reader);
tSWriter = new ThreadStart(writer);
tReader = new Thread(tSReader);
tWriter = new Thread(tSWriter);
try
{
client.Connect(clientEndPoint);
}
catch (SocketException e)
{
Console.WriteLine(e.ToString());
Console.ReadLine();
return;
}
tReader.Start();
tWriter.Start();
}
public static void writer()
{
string str;
byte[] data = new byte[1024];
nome = Console.ReadLine();
data = Encoding.ASCII.GetBytes(nome);
client.Send(data, data.Length, SocketFlags.None);
do
{
str = Console.ReadLine();
data = Encoding.ASCII.GetBytes(str);
client.Send(data, data.Length, SocketFlags.None);
} while (str != "exit");
client.Shutdown(SocketShutdown.Both);
tReader.Abort();
client.Close();
}
public static void reader()
{
byte[] data = new byte[1024];
int recv;
while (true)
{
try
{
recv = client.Receive(data);
}
catch (Exception e)
{
Console.WriteLine("Erro: " + e.Message);
Console.ReadLine();
break;
}
Console.WriteLine("\n" + Encoding.ASCII.GetString(data, 0, recv));
}
}
}
Someone can help me?
This is a program to search for strings from a file. The string required by the client is given from the client side, in my case, using telnet. The program I have written is a server side one. It accepts multiple clients.
But, the problems I am unable rectify are-
It doesn't check for strings from the file.
As soon as the client gets connected, the client cannot type in the strings they want to search in that particular file.
It doesn't send the reply back (i.e. If the string is present in the file or not) to the client. Its only shown on the server side.
How do I proceed further? Could someone tell me where am I going wrong? Could someone please help me out with the code?
This is my try at the program..
class Program
{
static void Main(string[] args)
{
IPAddress ipad = IPAddress.Parse("192.168.0.181");
TcpListener serversocket = new TcpListener(ipad, 8888);
TcpClient clientsocket = default(TcpClient);
Byte[] bytes = new Byte[256];
serversocket.Start();
Console.WriteLine(">> Server Started");
while(true)
{
clientsocket = serversocket.AcceptTcpClient();
Console.WriteLine("Accepted Connection From Client");
LineMatcher lm = new LineMatcher(clientsocket);
Thread thread = new Thread(new ThreadStart(lm.Run));
thread.Start();
Console.WriteLine("Client connected");
}
Console.WriteLine(" >> exit");
Console.ReadLine();
clientsocket.Close();
serversocket.Stop();
}
}
public class LineMatcher //I've jumbled it up here. Don't know what exactly to do..
{
public string fileName = "c:/myfile2.txt";
private TcpClient _client;
public LineMatcher(TcpClient client)
{
_client = client;
}
public void Run()
{
try
{
StreamReader sr = new StreamReader("c:/myfile2.txt");
using (var reader = new StreamReader(_client.GetStream()))
{
string line ="";
int lineNumber = 0;
while (null != (line = sr.ReadLine()))
{
lineNumber += 1;
byte[] data = new byte[1024];
NetworkStream stream = _client.GetStream();
//if (line.Equals(line))
for (int ct = stream.Read(data,0, data.Length-1); 0 < ct; ct = stream.Read(data,0,data.Length-1))
line += Encoding.ASCII.GetString(data, 0, ct);
line = line.Trim();
{
lineNumber.ToString();
data = Encoding.ASCII.GetBytes(line);
_client.Client.Send(data, data.Length, SocketFlags.None);
Console.WriteLine("Line {0} matches {1}", lineNumber, line);
}
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
Console.WriteLine("Closing client");
_client.Close();
}
}
I think you got some pieces in your Run-method swapped - here is a version that should do the job:
public void Run()
{
byte[] data;
try
{
using (var r = new StreamReader("c:/myfile2.txt"))
{
string line ="";
int lineNumber = 0;
while (null != (line = r.ReadLine()))
{
data = Encoding.ASCII.GetBytes(line + "\n");
_client.Client.Send(data, data.Length, SocketFlags.None);
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
Console.WriteLine("Closing client");
_client.Close();
}
Please note that I'm not 100% sure what you are trying to do (I think you want your textfile send line-by-line to your Terminal) - so you might have to change some bits here and there.
Don't know where the Stream-messes in your code came from but I guess you tried various tutorials/snippets and forgot to clean up ;)
i'm trying to write simple tcp\ip client-server.
here is server code:
internal class Program
{
private const int _localPort = 7777;
private static void Main(string[] args)
{
TcpListener Listener;
Socket ClientSock;
string data;
byte[] cldata = new byte[1024];
Listener = new TcpListener(_localPort);
Listener.Start();
Console.WriteLine("Waiting connections [" + Convert.ToString(_localPort) + "]...");
try
{
ClientSock = Listener.AcceptSocket();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
int i = 0;
if (ClientSock.Connected)
{
while (true)
{
try
{
i = ClientSock.Receive(cldata);
}
catch
{
}
try
{
if (i > 0)
{
data = Encoding.ASCII.GetString(cldata).Trim();
ClientSock.Send(cldata);
}
}
catch
{
ClientSock.Close();
Listener.Stop();
Console.WriteLine(
"Server closing. Reason: client offline. Type EXIT to quit the application.");
}
}
}
}
}
And here is client code:
void Main()
{
string data; // Юзерская дата
byte[] remdata ={ };
TcpClient Client = new TcpClient();
string ip = "127.0.0.1";
int port = 7777;
Console.WriteLine("\r\nConnecting to server...");
try
{
Client.Connect(ip, port);
}
catch
{
Console.WriteLine("Cannot connect to remote host!");
return;
}
Console.Write("done\r\nTo end, type 'END'");
Socket Sock = Client.Client;
while (true)
{
Console.Write("\r\n>");
data = Console.ReadLine();
if (data == "END")
break;
Sock.Send(Encoding.ASCII.GetBytes(data));
Sock.Receive(remdata);
Console.Write("\r\n<" + Encoding.ASCII.GetString(remdata));
}
Sock.Close();
Client.Close();
}
When i'm sending to my server i cannt receive data back answer. Sock.Receive(remdata) returns nothing! Why?
You're trying to receive to an empty buffer. You should allocate the buffer with a sensible size, and then take note of the amount of data received:
byte[] buffer = new byte[1024];
...
int bytesReceived = socket.Receive(buffer);
string text = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
(It's somewhat unconventional to use PascalCase for local variables, by the way. I'd also urge you not to just catch Exception blindly, and not to swallow exceptions without logging them.)