c# implementing timeout to read complete tcp packet by server - c#

In the tcp header packet their is a field which mentions the total size of packet. I have implemented my server which is listening to multiple client in following way
int numberOfClientsYouNeedToConnect = int.Parse(Console.ReadLine());
for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
{
Thread newThread = new Thread(new ThreadStart(Listeners));
newThread.Start();
}
public static void Listeners()
{
try
{
Socket socketForClient = tcpListener.AcceptSocket();
if (socketForClient.Connected)
{
Console.WriteLine("Client : " + socketForClient.RemoteEndPoint + " is now connected to server.");
NetworkStream networkStream = new NetworkStream(socketForClient);
//networkStream.ReadTimeout = 30;
System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);
while (true)
{
string theString = streamReader.ReadLine();
//Console.WriteLine(theString);
byte[] input_stream = extra_function.ConvertHexToString(theString);
for (int i = 0; i < input_stream.Length; i++)
{
// Console.WriteLine("hi");
Console.Write(input_stream[i]);
}
if (theString != "exit")
{
// original message from client
Console.WriteLine("------------------------------------------------------------------------------");
Console.WriteLine("Message recieved from client(" + socketForClient.RemoteEndPoint + ") : " + theString);
// ASCII code for the message from client
Console.Write("ASCII Code for message is : ");
foreach (char c in theString)
{
Console.Write(System.Convert.ToInt32(c) + " ");
}
}
}
But my problem is that server without receiving complete packet it starts processing it while other part of packet comes little later. So how can I change my code so that server receives complete packet and then process it. The size of the total packet is included in the header of packet. The server should wait till it receive that much bytes from client or wait till some time for getting complete packet.

Did you try StreamReader.ReadToEnd() instead of StreamReader.ReadLine() ?

Related

TCP message does not equal to what is sent in C#. How do I make it so it is?

When I send the message to the client and I try to check it with an if statement it doesn't equal to what I sent from the server.
What I want to do is: I want to send the keyword (here it's poop) and check it with an if statement on the client part.
If it finds that keyword with the if statement I want to execute some code.
For example:
Client code:
try {
TcpClient tcpclnt = new TcpClient();
Console.WriteLine("Connecting.....");
tcpclnt.Connect("127.0.0.1",8001);
Console.WriteLine("Connected");
Stream stm = tcpclnt.GetStream();
ASCIIEncoding asen= new ASCIIEncoding();
while(true)
{
byte[] bb=new byte[100];
int k=stm.Read(bb,0,100);
for (int i=0;i<k;i++)
{
var msg = Convert.ToChar(bb[i]).ToString();
if(msg == "poop")
{
Console.WriteLine("Poop executed.");
}
}
}
}
catch (Exception e) {
Console.WriteLine("Error..... " + e.StackTrace);
}
Server code (when the console reads my input I type "poop"):
try {
IPAddress ipAd = IPAddress.Parse("127.0.0.1");
TcpListener myList=new TcpListener(ipAd,8001);
myList.Start();
Console.WriteLine("The server is running at port 8001...");
Console.WriteLine("The local End point is :" +
myList.LocalEndpoint );
Console.WriteLine("Waiting for a connection.....");
Socket s=myList.AcceptSocket();
Console.WriteLine("Connection accepted from " + s.RemoteEndPoint);
ASCIIEncoding asen=new ASCIIEncoding();
while(true)
{
Console.Write("Msg to send: ");
var f = Console.ReadLine();
s.Send(asen.GetBytes(f));
}
s.Close();
myList.Stop();
}
catch (Exception e) {
Console.WriteLine("Error..... " + e.StackTrace);
}
The problem with your code is that you iterate over the byte array in which you wrote the received data. Therefore the message variable does always contain only one letter of your received message and is therefore never "poop" but "p", "o", "o", "p". To solve this issue you can use System.Text.Encoding to convert your byte array to a string:
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
var msg = System.Text.Encoding.UTF8.GetString(bb, 0, k);
if(msg == "poop")
{
// Do something
}
An even better solution would be to write back your received data into a temporary array until a defined end of string signal is received and only convert the temporary array if you are sure that everything is received.

C# Socket Server Continuously Reading

I just made a C# socket server and it works perfectly, but if I would like to make it to be able to listen the inputs the program crashes. My question is: how can I make to continuously listen after the clients commands.
Here is my code:
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace mc_server
{
class Program
{
private static TcpListener serverSocket;
private static TcpClient clientSocket;
private static StreamReader reader;
private static StreamWriter writer;
private static int PORT = 5000;
static void Main(string[] args)
{
Console.WriteLine(DateTime.Now.ToString() + " >> Server starting...");
StartServer();
Console.ReadKey(true);
serverSocket.Stop();
}
private static void StartServer()
{
try
{
serverSocket = new TcpListener(IPAddress.Any, PORT);
serverSocket.Start();
Console.WriteLine(DateTime.Now.ToString() + " >> Server started");
while (true)
{
clientSocket = serverSocket.AcceptTcpClient();
reader = new StreamReader(clientSocket.GetStream());
writer = new StreamWriter(clientSocket.GetStream());
StartListening();
}
}
catch (Exception e)
{
if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
Console.WriteLine(DateTime.Now.ToString() + " [ERR]: Internet connection unavailable! (" + e.ToString() + ")");
else
Console.WriteLine(DateTime.Now.ToString() + " [ERR]: Server can't be started! (" + e.ToString() + ")");
}
}
private static void StartListening()
{
try
{
string line;
//while (true)
//{
line = reader.ReadLine();
if (line.Contains("connected"))
{
Console.WriteLine(DateTime.Now.ToString() + " >> Remote connected");
}
else if (line.Contains("get_dir"))
{
Console.WriteLine("in_get_dir");
foreach (string directory in Directory.GetDirectories(path))
{
DirectoryInfo dir_name = new DirectoryInfo(directory);
string dirName = dir_name.Name;
writer.WriteLine(line);
}
}
//}
}
catch (Exception e)
{
Console.WriteLine(DateTime.Now.ToString() + " [ERR]: " + e.ToString() + ")");
}
}
}
}
Thank you so much for your help!
Regards, Stanley.
I just made a C# socket server and it works perfectly, but if I would like to make it to be able to listen the inputs the program crashes.
I am not sure what you meant by that, but I think you have a problem in receiving/reading the response.
serverSocket = new TcpListener(IPAddress.Any, PORT);
serverSocket.Start();
You've created a TcpListener named 'serverSocket'. Now let's create a socket that helps us send and receive data between the server and the client. Creating a Streamwriter and Streamreader is too long and complicated. You'll have to deal with flushing, disposing, and closing them.
Here's my 3 simplified guide of using Socket to communicate:
1.) Creating a Socket:
Socket socket = serverSocket.AcceptSocket(); // This is a
//synchronous function. It will not execute the next line until a client
//connects to the server
2.) Sending data:
socket.Send(Encoding.ASCII.GetBytes("I am sending a short text to
the client")); // This will send the text to client. It ONLY accepts byte
//array, therefore we have to convert it from string to byte array to be
//able
//to send it.
3.) Receiving/Reading Data:
// For Receiving Text from the Client
byte[] responseByteArray = new byte[socket.ReceiveBufferSize]; //
//This will create a byte array to store the data. socket.ReceiveBufferSize
//will tells us the length of the data sent in byte array (not string yet)
int responseLength = socket.Receive(responseByteArray); // Tells us
//the length of the response in byte array (not string yet)
string response = null; // We will create a variable 'response' to
//store the final result of the conversion
for (int i = 0; i < responseLength; i++) // Loop to convert All byte
//from byte array to string
{
response = response + (char)responseByteArray[i]; // Converts
//every single byte of character to char
}
Console.WriteLine(response); // Prints out the final result in
//string
You can use async/await keywords to read & write data asynchronously on the sockets.
That way, your input logic will stay separate. If you use async/await, you won't have to manage threads manually.

Accepting two client sockets as a server for a one-on-one game; mistake in tutorial?

I want to add network one-on-one support for my Battleship game, and found this tutorial regarding server-client network programming:
http://csharp.net-informations.com/communications/csharp-multi-threaded-server-socket.htm
The code I'm using is the following, more or less just taken from there with some adjustments:
public class HandleClient
{
TcpClient clientSocket;
string clientNumber;
public void StartClient(TcpClient inClientSocket, string clientNumber)
{
this.clientSocket = inClientSocket;
this.clientNumber = clientNumber;
Thread clientThread = new Thread(DoChat);
clientThread.Start();
}
private void DoChat()
{
int requestCount = 0;
byte[] inBytes = new byte[10025];
string dataFromClient = null;
byte[] outBytes = null;
string rCount;
string serverResponse = null;
while (true)
{
try
{
requestCount++;
NetworkStream stream = clientSocket.GetStream();
stream.Read(inBytes, 0, (int)clientSocket.ReceiveBufferSize);
dataFromClient = Encoding.ASCII.GetString(inBytes);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$$"));
Console.WriteLine(" >> From client " + clientNumber + dataFromClient);
rCount = Convert.ToString(requestCount);
serverResponse = "Server to client " + clientNumber + ": " + rCount;
outBytes = Encoding.ASCII.GetBytes(serverResponse);
stream.Write(outBytes, 0, outBytes.Length);
stream.Flush();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
and
class BattleshipServer
{
static void Main(string[] args)
{
TcpListener serverSocket = new TcpListener(IPAddress.Any, 8888);
TcpClient clientSocket = default(TcpClient);
int counter = 0;
serverSocket.Start();
while (true)
{
if (counter < 2)
{
counter++;
clientSocket = serverSocket.AcceptTcpClient();
Console.WriteLine("Client " + counter + " connected.");
HandleClient client = new HandleClient();
client.StartClient(clientSocket, counter.ToString());
}
}
clientSocket.Close();
serverSocket.Stop();
Console.WriteLine(" >> " + "exit");
Console.ReadLine();
}
}
However, I wonder about the last few lines just above this. Visual Studio complains about this code being unreachable, and I can see why. Is there any reason behind this code being there?
Also, I wonder what keeps counter from going up all the time? Is serverSocket.AcceptTcpClient() keeping the program "waiting" until another client connects maybe?
Thanks! And if you know of any other good sources to learn about this, I'll be glad to hear them :) Since I'd still have to adjust the above code by a good lot to make my game "wait" for data from the other player, restrict the player count, and so on.
The typo in the example (handleClinet()) may hint that the code was never reviewed; and you're right, the code won't leave the while block in this case.
The counter appears to serve as an identification of each client, as the introduction says "can handle multiple clients at the same time".
In your case, a one-on-one game, you probably want a single serverSocket.AcceptTcpClient and start the game after some basic information has been exchanged (ie. player names of both ends communicated), and you won't need that while loop there.

Async StreamWriter read and write C#

I've been coding a chat program that is made of two parts: server and client. The server uses TcpListener to listen for incoming requests to join the server, and the client uses TcpClient that it uses to connect to the server, and send messages. So far I have the handshake that is the first message sent when the client connects - it contains the client's IP address and the nickname set. I don't know how to make the server to listen asynchronously, because if it's not async, then the chat will be client -> server -> client -> server whereas it needs to be connected to multiple clients at once, and receive multiple messages at once. My code so far is written synchronously:
Client:
public void StartClient(string serverIP)
{
ReadWrite rw = new ReadWrite();
string nick = rw.GetNick();
string handshakeContents = "HANDSHAKE:" + nick + ":" + GetIP();
Int32 serverPort = 1336; // yay
TcpClient client = new TcpClient(serverIP, serverPort);
Console.WriteLine("Sending initial handshake: {0}", handshakeContents);
Byte[] data = System.Text.Encoding.ASCII.GetBytes(handshakeContents); // Convert handshakeContents to Byte[]
NetworkStream stream = client.GetStream(); // Instantiate object "stream" for use in read/write
stream.Write(data, 0, data.Length); // Send handshakeContents in Byte[] to server
Console.WriteLine(" - Connecting to IlanChat Server on ip {0}", serverIP);
Thread.Sleep(1000); // sleep 1s
data = new Byte[256];
string responseHandshake = String.Empty; // response handshake from server
Int32 bytes = stream.Read(data, 0, data.Length); // Read handshake.
responseHandshake = System.Text.Encoding.ASCII.GetString(data, 0, bytes); // Decode from Byte[] to ASCII string
Console.WriteLine(" - Received response handshake: {0}", responseHandshake);
Console.WriteLine(" - Successfully connected to IlanChat server on IP {0}", serverIP); // display message
Thread.Sleep(2000);
Console.Clear();
List<string> messagesRecieved = new List<string>();
while(true)
{
Console.Clear();
foreach (string msg in messagesRecieved)
{
Console.WriteLine(msg);
}
Console.WriteLine();
Console.Write("Enter message: ");
string msgRaw = Console.ReadLine();
string sendMsg = nick + ": " + msgRaw;
data = new Byte[256];
data = System.Text.Encoding.ASCII.GetBytes(sendMsg);
stream.Write(data, 0, data.Length); // finish this async shit
}
}
Server:
List<string> clientIP = new List<string>();
List<string> clientNicks = new List<string>();
string responseHandshake = "hello";
Int32 serverPort = 1336;
IPAddress machineIP = IPAddress.Parse(GetIP());
Console.Clear();
Console.WriteLine(" - Starting IlanChat server on IP {0}", machineIP);
TcpListener server = null;
server = new TcpListener(machineIP, serverPort);
server.Start();
Byte[] buffer = new Byte[256];
String data = null;
Console.WriteLine("Successfully started IlanChat server!");
while (true) // first alpha - only one user at a time
{
Console.WriteLine();
Console.WriteLine("Waiting for connections..");
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("User connecting..");
Console.WriteLine("Receiving handshake data..");
data = null;
NetworkStream stream = client.GetStream();
int i;
while ((i = stream.Read(buffer, 0, buffer.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(buffer, 0, i);
Console.WriteLine("Received handshake data: {0}", data);
Console.WriteLine("Processing data.."); // sample handshake: - HANDSHAKE:nick:ip
string tempNick = data.Replace("HANDSHAKE:", "");
string[] userDetails = tempNick.Split(':'); // should store to 0:nick, 1:ip
Console.WriteLine("Received client nick: {0}", userDetails[0]);
Console.WriteLine("Received client IP: {0}", userDetails[1]);
break;
}
Thread.Sleep(1100); // sleep
buffer = System.Text.Encoding.ASCII.GetBytes(responseHandshake);
Console.WriteLine("Sending response handshake..");
stream.Write(buffer, 0, buffer.Length);
}
Is there a way to make the server accept multiple connections at once, and maintain them? And is there a way to make the client receive multiple messages at once and type while refreshing the messages?
You need to look at using threading (Task library, async/await) to do what you want. Try looking here:
https://codereview.stackexchange.com/questions/29000/c-console-chat-server-async-await-tcpclient-tcplistener-networkstream-asyn
To get you started, assuming the logic in your code is correct you want to split up the server/client, something like this:
static void RunServer()
{
List<string> clientIP = new List<string>();
List<string> clientNicks = new List<string>();
string responseHandshake = "hello";
Int32 serverPort = 1336;
IPAddress machineIP = IPAddress.Parse(GetIP());
Console.Clear();
Console.WriteLine(" - Starting IlanChat server on IP {0}", machineIP);
TcpListener server = null;
server = new TcpListener(machineIP, serverPort);
server.Start();
Byte[] buffer = new Byte[256];
String data = null;
Console.WriteLine("Successfully started IlanChat server!");
while (true) // first alpha - only one user at a time
{
Console.WriteLine();
Console.WriteLine("Waiting for connections..");
TcpClient client = server.AcceptTcpClient();
Task.Run(() => RunClient(client));
}
}
static void RunClient(TcpClient client)
{
Byte[] buffer = new Byte[256];
Console.WriteLine("User connecting..");
Console.WriteLine("Receiving handshake data..");
String data = null;
string responseHandshake = "hello";
NetworkStream stream = client.GetStream();
int i;
while ((i = stream.Read(buffer, 0, buffer.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(buffer, 0, i);
Console.WriteLine("Received handshake data: {0}", data);
Console.WriteLine("Processing data.."); // sample handshake: - HANDSHAKE:nick:ip
string tempNick = data.Replace("HANDSHAKE:", "");
string[] userDetails = tempNick.Split(':'); // should store to 0:nick, 1:ip
Console.WriteLine("Received client nick: {0}", userDetails[0]);
Console.WriteLine("Received client IP: {0}", userDetails[1]);
break;
}
Thread.Sleep(1100); // sleep
buffer = System.Text.Encoding.ASCII.GetBytes(responseHandshake);
Console.WriteLine("Sending response handshake..");
stream.Write(buffer, 0, buffer.Length);
}

Server refuses to accept requests from clients

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 ;)

Categories