Telnet Server in C# :AsyncConnection in C# - c#

I am writing a telnet server When i Execute the following program my program is exiting
and it is displaying content in only 1 cmd.I have used TCP ASynchronously my content
is not displaying on 2cmd .Please help me regarding this issue.
public void Start()
{
Int32 port = 21;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
Console.WriteLine("Listening...");
StartAccept();
}
private void StartAccept()
{
// listener.BeginAcceptTcpClient(OnAccept, listener);
server.BeginAcceptTcpClient(HandleAsyncConnection, server);
}
private void HandleAsyncConnection(IAsyncResult res)
{
String data = null;
TcpListener listener = (TcpListener)res.AsyncState;
//listen for new connections again
TcpClient client = server.EndAcceptTcpClient(res);
Byte[] bytes = new Byte[256];
while (true)
{
server.Start();
// TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int b, i, a;
string str = null;
string str1 = null;
string str3 = null;
int k = 0;
int c = 0;
if (stream.CanWrite)
{
if (c == 0)
{
`enter code here`
byte[] Mybuff = Encoding.ASCII.GetBytes("Please Enter USer ID and Password");
stream.Write(Mybuff, 0, Mybuff.Length);
//StartAccept();
c++;
}
else
{
byte[] Mybuff = Encoding.ASCII.GetBytes("Please Enter USer ID and Password");
stream.Write(Mybuff, 0, Mybuff.Length);
StartAccept();
}
}
}
}

Try to add a Console.ReadLine(); after StartAccept(); to keep the console running.

If I understand correctly, you're trying to get what you type into console 1 to appear in console 2. Or at least to get the same data to appear in both console windows as sent by telnet commands from another console window.
If this is the case and you're using the same code to setup your command consoles then this won't work locally due to port clashes. The first command console doesn't reliquish ownership of port 21 for the second console to use.
On a windows machine it is now possible to implement port sharing using some WCF functionality. See here for more information.
It is normally advisable to use port numbers that aren't close to any other program when writing your own application. Say 17657 instead of 21, but this may be coloured by what your application intends to do.

Related

How to implement send and receive hl7 data in .NET in ssh connection

I'm implementing an application in .Net. I have to create a connection by SSH which is works, but the HL7 data receiving fails. The destination is a raspberry pi. So when I'm debugging the ssh client is connected, the port is forwarded, the tcp client also connected, but there is no answer for my queries. Plese suggest me some examples!
In this project I have already implemented it on Android - it works fine.
So in .Net I tried the NHapiTools library and I also tried the direct TcpClient way too. localPort = remotePort. I used localIP = "localhost"
static void Main(string[] args)
{
try
{
PrivateKeyFile file = new PrivateKeyFile(#"./key/private.key");
using (var client = new SshClient(remoteIP, sshPort, username, file))
{
client.Connect();
var ci = client.ConnectionInfo;
var port = new ForwardedPortLocal(localIP, localPort, client.ConnectionInfo.Host, remotePort);
client.AddForwardedPort(port);
port.Start();
var req = "MSH|^~\\&|TestAppName||AVR||20181107201939.357+0000||QRY^R02^QRY_R02|923456|P|2.5";
////TCP
var tcpClient = new TcpClient();
tcpClient.Connect(localIP, (int)localPort);
Byte[] data = System.Text.Encoding.ASCII.GetBytes(req);
using (var stream = tcpClient.GetStream())
{
stream.Write(data, 0, data.Length);
using (var buffer = new MemoryStream())
{
byte[] chunk = new byte[4096];
int bytesRead;
while ((bytesRead = stream.Read(chunk, 0, chunk.Length)) > 0)
{
buffer.Write(chunk, 0, bytesRead);
}
data = buffer.ToArray();
}
}
//I used this also with same result -> no respond
//SimpleMLLP
/*
var connection = new SimpleMLLPClient(localIP, localPort,
Encoding.UTF8);
var response = connection.SendHL7Message(req);
*/
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}
}
So I experinced that the buffer size is 0 in TCP (due to time out). In the SimpleMLLP test SendHK7Message method never returns
You are not implementing MLLP (also called LLP) protocol while sending message.
Description HEX ASCII Symbol
Message starting character 0B 11 <VT>
Message ending characters 1C,0D 28,13 <FS>,<CR>
This way, when you send a message to Listener (TCP/MLLP server), it looks for Start Block in your incoming data. It never finds it. It just discards your entire message considering garbage. Hence, you get nothing back from Listener.
With MLLP implemented, your message (the stuff you are writing on socket) should look something like below:
<VT>MSH|^~\\&|TestAppName||AVR||20181107201939.357+0000||QRY^R02^QRY_R02|923456|P|2.5<FS><CR>
Note the <VT>, <CR> and <FS> are place holders in above message.
You may refer to this article for detailed information (Read step 4 and onward):
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace SimpleMllpHl7ClientAdvanced
{
public class Program
{
private static char END_OF_BLOCK = '\u001c';
private static char START_OF_BLOCK = '\u000b';
private static char CARRIAGE_RETURN = (char)13;
static void Main(string[] args)
{
TcpClient ourTcpClient = null;
NetworkStream networkStream = null;
var testHl7MessageToTransmit = new StringBuilder();
//a HL7 test message that is enveloped with MLLP as described in my article
testHl7MessageToTransmit.Append(START_OF_BLOCK)
.Append("MSH|^~\\&|AcmeHIS|StJohn|CATH|StJohn|20061019172719||ORM^O01|MSGID12349876|P|2.3")
.Append(CARRIAGE_RETURN)
.Append("PID|||20301||Durden^Tyler^^^Mr.||19700312|M|||88 Punchward Dr.^^Los Angeles^CA^11221^USA|||||||")
.Append(CARRIAGE_RETURN)
.Append("PV1||O|OP^^||||4652^Paulson^Robert|||OP|||||||||9|||||||||||||||||||||||||20061019172717|20061019172718")
.Append(CARRIAGE_RETURN)
.Append("ORC|NW|20061019172719")
.Append(CARRIAGE_RETURN)
.Append("OBR|1|20061019172719||76770^Ultrasound: retroperitoneal^C4|||12349876")
.Append(CARRIAGE_RETURN)
.Append(END_OF_BLOCK)
.Append(CARRIAGE_RETURN);
try
{
//initiate a TCP client connection to local loopback address at port 1080
ourTcpClient = new TcpClient();
ourTcpClient.Connect(new IPEndPoint(IPAddress.Loopback, 1080));
Console.WriteLine("Connected to server....");
//get the IO stream on this connection to write to
networkStream = ourTcpClient.GetStream();
//use UTF-8 and either 8-bit encoding due to MLLP-related recommendations
var sendMessageByteBuffer = Encoding.UTF8.GetBytes(testHl7MessageToTransmit.ToString());
if (networkStream.CanWrite)
{
//send a message through this connection using the IO stream
networkStream.Write(sendMessageByteBuffer, 0, sendMessageByteBuffer.Length);
Console.WriteLine("Data was sent data to server successfully....");
var receiveMessageByteBuffer = Encoding.UTF8.GetBytes(testHl7MessageToTransmit.ToString());
var bytesReceivedFromServer = networkStream.Read(receiveMessageByteBuffer, 0, receiveMessageByteBuffer.Length);
// Our server for this example has been designed to echo back the message
// keep reading from this stream until the message is echoed back
while (bytesReceivedFromServer > 0)
{
if (networkStream.CanRead)
{
bytesReceivedFromServer = networkStream.Read(receiveMessageByteBuffer, 0, receiveMessageByteBuffer.Length);
if (bytesReceivedFromServer == 0)
{
break;
}
}
}
var receivedMessage = Encoding.UTF8.GetString(receiveMessageByteBuffer);
Console.WriteLine("Received message from server: {0}", receivedMessage);
}
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
catch (Exception ex)
{
//display any exceptions that occur to console
Console.WriteLine(ex.Message);
}
finally
{
//close the IO strem and the TCP connection
networkStream?.Close();
ourTcpClient?.Close();
}
}
}
}
You should modify your following line of code as below:
var req = START_OF_BLOCK + "MSH|^~\\&|TestAppName||AVR||20181107201939.357+0000||QRY^R02^QRY_R02|923456|P|2.5" + END_OF_BLOCK + CARRIAGE_RETURN;
For more open source code, you may refer to this github project.
After days of struggling I have solved the problem. The main error was with the port forwarding.
I would reccomend to use SSH.Net by Renci (There was algorithm error with Tamir ssh).
After ssh connection created I used this to port forward:
var port = new ForwardedPortLocal(localIP, localPort, "localhost", remotePort);
Check your localIP with ipconfig /all in cmd. Or use 127.0.0.1 as a loopback IP.
SimpleMLLPClient did not worked for me so I used the direct tcp client query way. Like this:
TcpClient ourTcpClient = new TcpClient();
ourTcpClient.Connect(localIP, (int)localPort);
NetworkStream networkStream = ourTcpClient.GetStream();
var sendMessageByteBuffer = Encoding.UTF8.GetBytes(testHl7MessageToTransmit.ToString());
if (networkStream.CanWrite)
{
networkStream.Write(sendMessageByteBuffer, 0, sendMessageByteBuffer.Length);
Console.WriteLine("Data was sent to server successfully....");
byte[] receiveMessageByteBuffer = new byte[ourTcpClient.ReceiveBufferSize];
var bytesReceivedFromServer = networkStream.Read(receiveMessageByteBuffer, 0, receiveMessageByteBuffer.Length);
if (bytesReceivedFromServer > 0 && networkStream.CanRead)
{
receivedMessage.Append(Encoding.UTF8.GetString(receiveMessageByteBuffer));
}
var message = receivedMessage.Replace("\0", string.Empty);
Console.WriteLine("Received message from server: {0}", message);
}
So it gave me instant answer with 0 bytes (not due timeout). And here comes Amit Joshi help. I used a query what he suggested with START_OF_BLOCK, CARRIAGE_RETURN and END_OF_BLOCK and finally started to work. Thank you Amit Joshi!
Additional info:
In Android (java/Kotlin) jsch session setPortForwardingL works fine with three params:
val session = jsch.getSession("user", sshIP, sshPort)
session.setPassword("")
jsch.addIdentity(privatekey.getAbsolutePath())
// Avoid asking for key confirmation
val prop = Properties()
prop.setProperty("StrictHostKeyChecking", "no")
session.setConfig(prop)
session.connect(5000)
session.setPortForwardingL(localForwardPort, "localhost", remotePort)
val useTls = false
val context = DefaultHapiContext()
connection = context.newClient("localhost", localForwardPort, useTls)

C# and Processing socket communication

I am trying to develop a software (in C#) that collect some data on a list (List<string> socketList). The value of this list must be sent to a processing software.
In this program, the server (the C# software) waits for a message from a client (the Processing software) and send an element of the list. This list is continuously filled by a method in another thread (I verify, the list is everytime full). I used this method because I need that each value has to arrive at a client, no matter the speed.
Here there is the method in C# (it is launched as a thread):
public static void InizializeSocket()
{
//setting the comunication port
int port = 5000;
//infinite loop in order to accept sequential clients
while (true)
{
//I open the listener for any IP
TcpListener listener = new TcpListener(IPAddress.Any, port);
Console.WriteLine("Listening...");
//Waiting for a client
listener.Start();
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("CONNECTED");
//this string will contain the client message
String dataReceived = "";
//loop until "q". If the client send a message with a q, the server disconnect the client
while (dataReceived != "q")
{
//Read the client message
NetworkStream nwStream = client.GetStream();
try
{
//Define the client message buffer dimension and read the message
byte[] buffer = new byte[client.ReceiveBufferSize];
int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
//Encoding the byte in a string
dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
//check if the List<string> socketList is not empty. If it has any elements, I send the first one and after that I remove the element from the list
if (socketList.Count > 0)
{
//Encoding the string in a byte
byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(socketList[0]);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
socketList.RemoveAt(0);
}
nwStream.Flush();
}
catch (Exception e) { dataReceived = "q"; }
}
//Exit from the client loop
Console.WriteLine("DISCONNECTED");
client.Close();
listener.Stop();
}
}
And here the simple Processing software
import processing.net.*;
Client myClient;
String dataIn;
int port = 5000;
String ip = "127.0.0.1";
void setup () {
size(1100, 1025);
//Initialize the client
myClient = new Client(this, "127.0.0.1", 5000);
}
void draw () {
//If the client is available it send a generic message to the server and try to receive a response
if (myClient.available() > 0) {
myClient.write("c");
dataIn = myClient.readString();
}
//print the output in debug
println(dataIn);
}
Here the Processing software is able to connect, anyway, I received every time null.
In addition, if I try to write (in the try on the C# software) only:
if (socketList.Count > 0)
{
byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(socketList[0]);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
socketList.RemoveAt(0);
}
I receive strange values that are not the same values in the list stored in C# software.
So, why in the first case processing read only null value? And why in the second case it read "random" value?
EDIT:
Analyze better the programs flow, I verify where is the problem. I rewrite the processing socket as a java socket. It is launched in another thread and fills an ArrayList.
Considering a simplification of the code (in order to understand better), if I write:
Socket s = new Socket("localhost", 5000);
BufferedReader input =new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out= new PrintWriter(s.getOutputStream(), true);
out.println("hello");
String temp = input.readLine();
the software blocks on String temp = input.readLine();. Anyway, the communication is established and I am sure that C# send the string.

C# FTP server never receives incoming transfer connection after processing EPRT command

I am building an FTP server that will get images from a camera and store the photos in a local directory. I am having issues grabbing the file from the port given to me. Here is the conversation:
Server(me):"220 Ready!"
Client:"USER Guest"
Server: "331 Username ok, need password"
Client:"PASS "
Server: "230 user logged in"
Client: "PWD"
Server: "257 \"/\""
Client: "EPRT |1|172.22.22.103|58719|
Server:"500 IDK"
Client: "PORT 172,22,22,103,147,237"
Server:"200 Ready for Transport"
Client: "TYPE I"
Server:"200 I understand it is an image file"
Client: "STOR .TEST.RHPRYI"
I found the port by converting the last two numbers to hexadecimal (93,ED) appending them and then converting back to decimal. My final port is 37869.
I then create a new TcpClient to use as a download, but my TcpListener never picks up the camera. Also I am not sure my download method is correct.
I got lots of my code from here:
http://www.codeproject.com/Articles/380769/Creating-an-FTP-Server-in-Csharp-with-IPv-Support
Really my question comes down to: How do I get the file being sent by the client as an FTP server in C#?
Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Drawing;
using Microsoft.VisualBasic;
//Creates a TcpServer that is used to transfer images from the Axis Camera to a directory on a computer
//ftpdmin was chosen as the name because it was supposed to be a replica of a program in c just made in csharp
//However, it was really hard to transfer from c because all of the struct names and functions were nonintuitive
//This program is completely made from internet sources, and there are definitely bugs. For instance it does not implement
// many FTP calls.
namespace ftpdmin
{
class Server
{
//TCPListener listens to a given IP and port to wait for a connection with the camera
//Download Listener listens to the port given by the camera in the PORT command, which is the
//port at which the files needed to be downloaded are stored.
//Listen thread implements tcpListener. We do not want to be stuck in an infinite loop, but
//we always want to be listening to the camera. That is why we use another thread.
//Downlaod thread implements the downloadlistener for the same reason as above
//File name is the download files name given by the camera in the STOR command.
//direct is the directory to save the files at on the local computer. It was given in the main
// method of the console program. See Program.cs
private TcpListener tcpListener;
private TcpListener downloadListener;
private Thread listenThread;
private Thread downloadThread;
private string fileName;
private string direct;
//Initialize Ip adress and threads
public Server(string dir)
{
direct = dir;
this.tcpListener = new TcpListener(IPAddress.Parse("172.22.22.104"), 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
//Start listening
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private void ListenForDownloads()
{
this.downloadThread.Start();
while(true)
{
TcpClient downloadClient = this.downloadListener.AcceptTcpClient();
Thread clientDownloadThread = new Thread(new ParameterizedThreadStart(HandleClientDownload));
clientDownloadThread.Start(downloadClient);
}
}
private void HandleClientDownload(object downloadClient)
{
Console.WriteLine("IM HERE");
TcpClient downloaderClient = (TcpClient) downloadClient;
NetworkStream downloadStream = downloaderClient.GetStream();
StreamWriter downloadWriter = new StreamWriter(downloadStream, Encoding.ASCII);
StreamReader downloadReader = new StreamReader(downloadStream);
try
{
//Sets up the path to store the file
string path = Path.Combine(direct, fileName);
FileStream file = File.Create(path);
//Implements the method to download a file
CopyStream(file, downloadStream);
file.Close();
}
catch (Exception e)
{
Console.WriteLine("a socket error has occured:" + e);
}
}
private void HandleClientComm(object client)
{
//A Server is TCP has to respond to a bunch of commands from the client. The first thing it
//does when it connects is send code 220 which says it is good to continue.
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
StreamWriter writer = new StreamWriter(clientStream, Encoding.ASCII);
StreamReader reader=new StreamReader(clientStream);
writer.WriteLine("220 Ready!");
writer.Flush();
string command=reader.ReadLine().ToUpperInvariant();
int downloadPort=0;
string ipOfDownload="";
Console.WriteLine(command);
while(!command.Equals("QUIT"))
{
//USER comes with the username given to the client. Here I do not check if the cameras username
//is the same as the username in the program. I just give the command 331 which means continue.
if(command.Contains("USER"))
{
writer.WriteLine("331 Username ok, need password");
writer.Flush();
}
//PASS is the same as username. I do not check the passwords, I just give 230 which continues the FTP.
else if(command.Contains("PASS"))
{
writer.WriteLine("230 User Logged In");
writer.Flush();
}
//PWD is Print working directory. I send 257 to say I have a PWD, and I send / because that is what is saved
// in the camera. I am not actually going to save files at this directory, I just want to continue.
else if(command.Contains("PWD"))
{
writer.WriteLine("257 \"/\"");
writer.Flush();
}
//This is an important command. The client is sending an IP where it wants to do file transfers. It comes in a
//Weird format so all this function is doing is allowing me store Ip as "172.22.22.103" instead of "PORT 172,22,22,103"
//Also there is a port listed at the end, but it is given in 2 numbers. The conversion to one port number is done by
//changing the two numbers to hexadecimal, appending them, and then transforming them back to decimal.
else if(command.Contains("PORT"))
{
string portPart1 = "";
string portPart2 = "";
Console.WriteLine(command);
int numberOfCommas=0;
int i=0;
bool notPort=true;
bool isNotPortPart2=true;
while(i<command.Length && notPort)
{
if(command[i].Equals(','))
{
if(numberOfCommas==3)
{
notPort=false;
}
else
{
ipOfDownload+=".";
numberOfCommas++;
}
}
else if(Information.IsNumeric(command[i]))
{
ipOfDownload+=command[i];
}
i++;
}
while(i<command.Length && isNotPortPart2)
{
if(Information.IsNumeric(command[i]))
{
portPart1+=command[i];
}
else
{
isNotPortPart2=false;
}
i++;
}
while(i<command.Length)
{
portPart2+=command[i];
i++;
}
Console.WriteLine("IP=" +ipOfDownload);
Console.WriteLine("PortPart1="+portPart1);
Console.WriteLine("PortPart2="+portPart2);
int portPart1int = int.Parse(portPart1);
int portPart2int = int.Parse(portPart2);
string portPart1Hex = portPart1int.ToString("X");
string portPart2Hex = portPart2int.ToString("X");
string downloadPortHex = portPart1Hex + portPart2Hex;
downloadPort = Convert.ToInt32(downloadPortHex, 16);
Console.WriteLine("PortPart1Hex=" + portPart1Hex);
Console.WriteLine("PortPart2Hex=" + portPart2Hex);
Console.WriteLine("FinalPort: " + downloadPort);
this.downloadListener = new TcpListener(IPAddress.Parse(ipOfDownload), downloadPort);
this.downloadThread = new Thread(new ThreadStart(ListenForDownloads));
writer.WriteLine("200 Ready for Transport");
writer.Flush();
}
//The client sends TYPE I for image. usually an ftp would switchto binary mode because that is the only way
//a file can be transferred cleanly.
else if(command.Contains("TYPE"))
{
writer.WriteLine("200 I understand it is an image file");
writer.Flush();
}
//This command gives the name of the file being transferred. I substring to get rid of
//The STOR . that comes before the file name
else if(command.Contains("STOR"))
{
fileName = command.Substring(6);
Console.WriteLine(fileName);
}
//For all other commands sent by the client, I send 500 which means I'm not implementing those commands.
else
{
writer.WriteLine("500 IDK");
writer.Flush();
}
command=reader.ReadLine().ToUpperInvariant();
Console.WriteLine(command);
}
writer.WriteLine("221 BYE");
writer.Flush();
tcpClient.Close();
}
private static long CopyStream(Stream input, Stream output, int bufferSize)
{
byte[] buffer = new byte[bufferSize];
int count = 0;
long total = 0;
while ((count = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, count);
total += count;
}
return total;
}
private static long CopyStreamAscii(Stream input, Stream output, int bufferSize)
{
char[] buffer = new char[bufferSize];
int count = 0;
long total = 0;
using (StreamReader rdr = new StreamReader(input))
{
using (StreamWriter wtr = new StreamWriter(output, Encoding.ASCII))
{
while ((count = rdr.Read(buffer, 0, buffer.Length)) > 0)
{
wtr.Write(buffer, 0, count);
total += count;
}
}
}
return total;
}
private long CopyStream(Stream input, Stream output)
{
//if (_transferType == "I")
//{
return CopyStream(input, output, 4096);
//}
//else
//{
// return CopyStreamAscii(input, output, 4096);
//}
}
}
By the ERTP (or PORT) command, the client tells your server where the client is listening for incoming transfer connections to be initiated by the server. Instead you start listening too. So both parties are listening and nothing can happen.
So instead of TcpListener, you need to create TcpClient and actively connect.
See RFC 2428.
What you have implemented resembles passive mode (EPSV or PASV command), while the client is using an active mode.
Anyway you should better use an existing implementation of FTP server instead of trying to implement your own.

Socket programming using C# based on thread loses the data

I am working on a transportation Project RailWay. Let me explain the project :there are a lot of sensors during the path of the train ,so when the train passes one of these sensors ,the sensor sends a value to CTC(A computer that manages the sensors) server the value is 1 or 0 ,1 means that the train arrive the sensor and 0 means the train left the sensor ,so every thing is ok ,now here is the scope of my project:
The CTC server send the value to MY-SERVER for example :ID=16(SENSOR-ID),state=0.it means that the train left the sensor that its id is 16 ,Note:That i know the location of sensors by id .so My problems start here : the CTC server sends its data by TCP ,so i have to create a listener to listen the data that comes from the CTC server ,(Note:Sometimes the data that comes from CTC is a lot and maybe some data be lost) ,I create a program using c# that listen the port but sometimes the data that coes fro CTC are lost why ?
So let me explain my programs:
It's the code that i wrote to get the data :
class Server
{
private TcpListener tcpListener;
private Thread listenThread;
public Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 3456);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.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
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
}
tcpClient.Close();
}
}
And here i call the server class :
class Program
{
static void Main(string[] args)
{
Server obj=new Server();
}
}
The CTC code that sends data is like this(An example) :
static void Main(string[] args)
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3456);
client.Connect(serverEndPoint);
using (NetworkStream clientStream = client.GetStream())
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Server!");
clientStream.Write(buffer, 0, buffer.Length);
}
}
But sometimes my programs(SERVER CODE) lost data ?!!!Why ?Any idea ?
Best regards
Here is my solution of a basic Client/Server application using StreamReader and StreamWriter
Basic structure
The server will be running a TcpListener. We will use the Pending() method to check for waiting connections while not blocking the thread from exiting. When a new connection is waiting we will accept it with the AcceptTcpClient(), create a new instance of our own Client class and add it to a List<Client()> to mange it later. The class Client will store the methods to send data and hold informations like ID etc.
Code
Server Class:
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace CTCServer
{
class Server
{
//Stores the IP Adress the server listens on
private IPAddress ip;
//Stores the port the server listens on
private int port;
//Stores the counter of connected clients. *Note* The counter only gets increased, it acts as "id"
private int clientCount = 0;
//Defines if the server is running. When chaning to false the server will stop and disconnect all clients.
private bool running = true;
//Stores all connected clients.
public List<Client> clients = new List<Client>();
//Event to pass recived data to the main class
public delegate void GotDataFromCTCHandler(object sender, string msg);
public event GotDataFromCTCHandler GotDataFromCTC;
//Constructor for Server. If autoStart is true, the server will automaticly start listening.
public Server(IPAddress ip, int port, bool autoStart = false)
{
this.ip = ip;
this.port = port;
if (autoStart)
this.Run();
}
//Starts the server.
public void Run()
{
//Run in new thread. Otherwise the whole application would be blocked
new Thread(() =>
{
//Init TcpListener
TcpListener listener = new TcpListener(this.ip, this.port);
//Start listener
listener.Start();
//While the server should run
while (running)
{
//Check if someone wants to connect
if (listener.Pending())
{
//Client connection incoming. Accept, setup data incoming event and add to client list
Client client = new Client(listener.AcceptTcpClient(), this.clientCount);
//Declare event
client.internalGotDataFromCTC += GotDataFromClient;
//Add to list
clients.Add(client);
//Increase client count
this.clientCount++;
}
else
{
//No new connections. Sleep a little to prevent CPU from going to 100%
Thread.Sleep(100);
}
}
//When we land here running were set to false or another problem occured. Stop server and disconnect all.
Stop();
}).Start(); //Start thread. Lambda \(o.o)/
}
//Fires event for the user
private void GotDataFromClient(object sender, string data)
{
//Data gets passed to parent class
GotDataFromCTC(sender, data);
}
//Send string "data" to all clients in list "clients"
public void SendToAll(string data)
{
//Call send method on every client. Lambda \(o.o)/
this.clients.ForEach(client => client.Send(data));
}
//Stop server
public void Stop()
{
//Exit listening loop
this.running = false;
//Disconnect every client in list "client". Lambda \(o.o)/
this.clients.ForEach(client => client.Close());
//Clear clients.
this.clients.Clear();
}
}
}
Client Class
using System.IO;
using System.Net.Sockets;
using System.Threading;
namespace CTCServer
{
class Client
{
//Stores the TcpClient
private TcpClient client;
//Stores the StreamWriter. Used to write to client
private StreamWriter writer;
//Stores the StreamReader. Used to recive data from client
private StreamReader reader;
//Defines if the client shuld look for incoming data
private bool listen = true;
//Stores clientID. ClientID = clientCount on connection time
public int id;
//Event to pass recived data to the server class
public delegate void internalGotDataFromCTCHandler(object sender, string msg);
public event internalGotDataFromCTCHandler internalGotDataFromCTC;
//Constructor
public Client(TcpClient client, int id)
{
//Assain members
this.client = client;
this.id = id;
//Init the StreamWriter
writer = new StreamWriter(this.client.GetStream());
reader = new StreamReader(this.client.GetStream());
new Thread(() =>
{
Listen(reader);
}).Start();
}
//Reads data from the connection and fires an event wih the recived data
public void Listen(StreamReader reader)
{
//While we should look for new data
while(listen)
{
//Read whole lines. This will read from start until \r\n" is recived!
string input = reader.ReadLine();
//If input is null the client disconnected. Tell the user about that and close connection.
if (input == null)
{
//Inform user
input = "Client with ID " + this.id + " disconnceted.";
internalGotDataFromCTC(this, input);
//Close
Close();
//Exit thread.
return;
}
internalGotDataFromCTC(this, input);
}
}
//Sends the string "data" to the client
public void Send(string data)
{
//Write and flush data
writer.WriteLine(data);
writer.Flush();
}
//Closes the connection
public void Close()
{
//Stop listening
listen = false;
//Close streamwriter FIRST
writer.Close();
//Then close connection
client.Close();
}
}
}
Test code. Note: this is a console application!
using System;
using System.Net;
namespace CTCServer
{
class Program
{
static void Main(string[] args)
{
//Set title
Console.Title = "CTC-Server";
//Create new instance of the server
Server server = new Server(IPAddress.Any, 1221);
//Handle GotDataFromCTC
server.GotDataFromCTC += GotDataFromCTC;
//Start the server. We could use the autoStart in constructor too.
server.Run();
//Inform about the running server
Console.WriteLine("Server running");
//Listen for input.
while(true)
{
//Read input line from cmd
string input = Console.ReadLine();
//Stores the command itself
string command;
//Stores parameters
string param = "";
//If input line contains a whitespace we have parameters that need to be processed.
if(input.Contains(" "))
{
//Split the command from the parameter. Parte before whitespace = command, rest = parameters
command = input.Split(' ')[0];
param = input.Substring(command.Length +1);
}
else
{
//No whitespace, so we dont have any parameters. Use whole input line as command.
command = input;
}
//Process the command
switch(command)
{
//Sends a string to all clients. Everything behind "send " (Note the whitespace) will be send to the client. Exanple "send hello!" will send "hello!" to the client.
case "send":
{
//Give some feedback
Console.WriteLine("Send to all clients: {0}", param);
//Send data
server.SendToAll(param);
//Done
break;
}
//Closes connection to all clients and exits. No parameters.
case "exit":
{
//Stop the server. This will disconncet all clients too.
server.Stop();
//Clean exit
Environment.Exit(0);
//Done. We wont get here anyway.
break;
}
}
}
}
//Recived data from clien. Show it!
static void GotDataFromCTC(object sender, string data)
{
Console.WriteLine("Data from CTC-Server with ID {0} recived:\r\n{1}", (sender as Client).id, data);
}
}
}
NOTE that this application doesnt have any exception handling. I did this to show a direction, you will need to modify the code to fit to your requirements. Let me know if you need something.
Example Project (Visual Studio 2013 Pro): Download | Virustoal
I found an article about Socket programming that using StreamReader ,It using one thread ,and no information lost is happened
You can take a look here :
http://www.codeproject.com/Articles/511814/Multi-client-per-one-server-socket-programming-in

C# TCP Chat Application Threading

I am in desperate need of help. I have essentially created a program that (will use) encryption to send messages back and forth. The encryption part is working fine, however I am fairly new to Threads and I can not for the life of me get my Client/Server pieces of the application to line up. The chat program is direct IP connection using TCP, so each host is a client and a server. The issue I appear to be having, when I debug, is that the server thread is either not ready when the Client tries to connect to it, or if it is ready it will not relinquish the Thread so the Client can connect! I have been working on this for hours and it is very frustrating.. I hope someone can help! I've included my code below.
This is my code snippet from my MainForm, which constructs the Client and Server aspects:
private void InitializeComponent() {
server = new ServerSide("127.0.0.1",7865);
servThread = new Thread(new ThreadStart(server.begin));
client = new ClientSide("127.0.0.1",7865);
clientThread = new Thread(new ThreadStart(client.begin));
servThread.Start();
clientThread.Start();
//servThread.Join();
//clientThread.Join();
}
This is my ServerSide code:
public class ServerSide
{
String IpString;
int tcpPort;
bool goodToGo = false;
System.Net.IPAddress ipAddress = null;
public ServerSide(String ip, int tcpPort)
{
IpString = ip;
bool isValidIp = System.Net.IPAddress.TryParse(IpString, out ipAddress);
if (isValidIp == true) // check if the IP is valid, set the bool to true if so
{
goodToGo = true;
}
else
{
goodToGo = false;
}
}
public void begin()
{
try
{
IPAddress ipAd = IPAddress.Parse(IpString);
/* Initializes the Listener */
TcpListener myList = new TcpListener(ipAd, tcpPort);
Socket s = null;
/* Start Listening at the specified port */
while (true)
{
myList.Start();
if (myList.Pending())
{
s = myList.AcceptSocket();
break;
}
}
String toReceive = "";
while (true)
{
byte[] b = new byte[4096];
int k = s.Receive(b);
for (int i = 0; i < k; i++)
toReceive += Convert.ToString((Convert.ToChar(b[i])));
// ASCIIEncoding asen = new ASCIIEncoding();
var form = MainForm.ActiveForm as MainForm;
if (form != null)
{
form.messageReceived(toReceive);
}
toReceive = "";
}
}
catch (Exception e)
{
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
}
ClientSide code:
public class ClientSide
{
private String IpString;
private int tcpPort;
private TcpClient tcpInt;
private static Stream stm;
private System.Net.IPAddress ipAddress = null;
private bool goodToGo = false;
public ClientSide(String ip, int tcpPort)
{
IpString = ip;
this.tcpPort = tcpPort;
bool isValidIp = System.Net.IPAddress.TryParse(IpString, out ipAddress);
if (isValidIp == true)
{
goodToGo = true;
}
else
{
goodToGo = false;
}
}
public void begin()
{
try
{
tcpInt = new TcpClient();
// Console.WriteLine("Connecting.....");
tcpInt.Connect(IpString, tcpPort);
// use the ipaddress as in the server program
// Console.WriteLine("Connected");
// String str = Console.ReadLine();
stm = tcpInt.GetStream();
}
catch (Exception e)
{
Console.WriteLine("Error..... " + e.StackTrace);
}
}
public void sendMessage(String str)
{
// stm = tcpInt.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);
for (int i = 0; i < k; i++)
Console.Write(Convert.ToChar(bb[i]));*/
}
}
}
Once again.. what typically happens is my Client receives an error that the host actively refused the connection.. but I do not know how to time them. I am looking for how to have my server listening for TCP Connections, but still manage to go to my other thread to create the TCP Connecion to send the server (I am testing this on localhost currently).
Thanks.
In the constructor of the ServerSide class, you forgot to initialize the tcpPort member. Because you forgot, the server will try to listen to port 0 and the client will try to connect to port 7865, and it will fail.
Try adding this code to the constructor in the ServerSide class.
this.tcpPort = tcpPort;
As for the threads, you might have a problem if the client thread tries to connect before the server thread has started listening. You can use a loop to try to connect a number of times (let's say 10), with a timeout (let's say 1 second) if you don't succeed. This way, you will retry 10 times and give up after that.

Categories

Resources