How to send multiple messages over a socket - c#

I saw on the internet how to create a socket server in C#,
after sending to the server one message the server closes.
I have been wondering what can I do to change it so it can handle multiple messages.
The code:
static void startServer() {
Console.WriteLine("[*] Opening server...");
TcpListener listener = new TcpListener(IPAddress.Any, 45784);
listener.Start();
Console.WriteLine("[*] Server waiting on port " + 45784);
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client connected!");
StreamReader STR = new StreamReader(client.GetStream());
Console.WriteLine(STR.ReadLine());
}
static void Main(string[] args)
{
string ip = GetIpAdress();
Console.WriteLine("server on: " + ip);
startServer();
Console.Read();
}

I believe this is pretty basic. Simply put your code read only one message and exit.
To read multiple message you just need to put a while loop around this line.
Console.WriteLine(STR.ReadLine());

Your server is stopping after receiving one message because that's all you've told it to do (so far).
These lines:
StreamReader STR = new StreamReader(client.GetStream());
Console.WriteLine(STR.ReadLine());
Will handle one message from the client, and then stop since you aren't telling it to grab another message.
If you want the server to listen and handle an arbitrary number of messages, you'll want to put this code in a loop.
Try this:
static TcpListener StartServer()
{
Console.WriteLine("[*] Opening server...");
TcpListener listener = new TcpListener(IPAddress.Any, 45784);
listener.Start();
Console.WriteLine("[*] Server waiting on port " + 45784);
return listener;
}
static void Listen(CancellationToken cancellationToken)
{
string ip = GetIpAddress();
Console.WriteLine("server on: ");
var listener = StartServer();
var client = listener.AcceptTcpClient();
Console.WriteLine("Client connected!");
var reader = new StreamReader(client.GetStream());
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine(reader.ReadLine());
}
}
static void Main(string[] args)
{
var cancellationSource = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cancellationSource.Cancel();
};
Listen(cancellationSource.Token);
}
This code will continue to get lines from the remote client until the server is canceled with Ctrl-C. It uses a CancellationToken to hook into the cancellation event, but you could also use a bool flag if you wanted.
Caveats: This only accepts messages from a single client, not multiple clients (that's a different challenge). Also, once the cancel event is sent, the server waits for one more message from the client before exiting and closing the connection, because ReadLine() blocks the thread until it sees a message come in.

I meant, multiple messages, one after the other from a single client.
You need to add some loops.
listener.Start();
while(true) { // beware: please avoid never-ending loop, and define a proper exit condition
TcpClient client = listener.AcceptTcpClient();
using(client) {
Console.WriteLine("Client connected!");
StreamReader STR = new StreamReader(client.GetStream());
string s = STR.ReadLine();
while(s != null) { // read until EOF
Console.WriteLine(s);
}
}
}
listener.Stop(); // this should always be called after exit condition occurs

Related

TCP/IP Continuously receive message without closing the connection

I've been watching the following pair of videos on how to create a TCP/IP connection : Server and Client
What I need to do is create a game (flipcard) in which I send only 2 coordinates for a matrix. Nothing more. Or less.
(the code will follow)
From what I've observed, he closes and reopens the connection, everytime he send a message. It's working. But what do I modify in the code to keep the connection open and detect when a message arrived ?
All my google-searches brought me to these 2 methods:
I have had luck using the socket object directly (rather than the TCP client). (But I do not want to use sockets)
Also uses sockets
When I click to start the server
private void bStartServer_Click(object sender, EventArgs e)
{
Thread tcpServerRunThread = new Thread(new ThreadStart(TCPServerRun));
tcpServerRunThread.Start();
}
Server Runs and waits for a connection
private void TCPServerRun()
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 2016);
tcpListener.Start();
updateUI("Listening");
while (true)
{
TcpClient client = tcpListener.AcceptTcpClient();
updateUI("Connected");
Thread tcpHandlerThread = new Thread(new ParameterizedThreadStart(tcpHandler));
tcpHandlerThread.Start(client);
}
}
I handle my message
private void tcpHandler(object client)
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 5004);
TcpClient mClient = (TcpClient)client;
NetworkStream stream = mClient.GetStream();
byte[] message = new byte[1024];
stream.Read(message,0, message.Length);
updateUI("New message = " + Encoding.ASCII.GetString(message));
stream.Close();
mClient.Close();
}
NOTE: updateUI is a function made by him to update a listbox item
Client side - almost like the server side
`private void button1_Click(object sender, EventArgs e)
{
Thread mThread = new Thread(new ThreadStart(ConnectAsClient));
mThread.Start();
}
private void ConnectAsClient()
{
// aici putem inlocui cu adresa de IP dorita
//client.Connect(IPAddress.Parse(textBox.Text), 5004);
client = new TcpClient();
//client.Connect(IPAddress.Parse("127.0.0.1"), 2016); // for when I'm not connected to network
client.Connect(IPAddress.Parse("my_ip_here"), 2016); // for when I am connected to the network
updateUI("connected");
NetworkStream stream = client.GetStream();
string s = "Hello world!";
byte[] message = Encoding.ASCII.GetBytes(s);
stream.Write(message, 0, message.Length);
this.updateUI("Message sent!");
stream.Close();
// client.Close();
}`
If I'm not wrong, everytime he connects again, he creates a new connection, and not open the old one, right?
(It's my first time using TCP/IP, learning on my own, so I'd rather not use sockets, if possible)
-----------------------------------------------------------------------
Full link to my code (slighty modified from the videos provided at the beginning):
TCPClient
TCPServer
You are reconnecting every time you send the message. Use two different methods for this; one for connecting to the server and then another one for actually sending the message. Like so:
TcpClient client;
private void ConnectAsClient()
{
//client.Connect(IPAddress.Parse(textBox.Text), 5004);
client = new TcpClient();
//client.Connect(IPAddress.Parse("127.0.0.1"), 2016);
client.Connect(IPAddress.Parse("my_ip_here"), 2016);
updateUI("connected");
}
void SendMessage()
{
NetworkStream stream = client.GetStream();
string s = "Hello world!";
byte[] message = Encoding.ASCII.GetBytes(s);
stream.Write(message, 0, message.Length);
this.updateUI("Message sent!");
}

TCP IP Listener in windows Service

I'm trying to create a windows service that needs to run in the background and listen for incoming traffic (a normal and regular TCP listener)
my code is:
private TcpListener server;
public void startServer()
{
// EventLog.WriteEntry(source, "connected on: " + ipAddress.ToString() + " port: " + Service1.Port.ToString());
server = new TcpListener(IPAddress.Parse("127.0.0.1"), Service1.Port);
server.Start();
while (true)
{
var client = server.AcceptTcpClient();
new Thread(work).Start(client);
}
public void work(object client)
{
string msg = null;
var clientLocal = (TcpClient)client;
using (NetworkStream ns = clientLocal.GetStream())
using (StreamReader sr = new StreamReader(ns))
{
byte[] msgFullArray = new UTF8Encoding(true).GetBytes(msg);
fs.Write(msgFullArray, 0, msg.Length);
}
now if you don't look at the work method at all as whenever i start my service it freezes whenever i try to start it at my :
var client = server.AcceptTcpClient();
meaning my service never gets to use the Thread or my Work method..
i can see from previous logging that it enters my while loop and then just times out the service
In your OnStart Method you have to instantiate a server class.
protected override void OnStart(string[] args)
{
// Create the Server Object ans Start it.
server = new TCPServer();
server.StartServer();
}
that is responsible to handle the connections to the server by creating a new Thread (so that it is a non-blocking process)
public void StartServer()
{
if (m_server!=null)
{
// Create a ArrayList for storing SocketListeners before
// starting the server.
m_socketListenersList = new ArrayList();
// Start the Server and start the thread to listen client
// requests.
m_server.Start();
m_serverThread = new Thread(new ThreadStart(ServerThreadStart));
m_serverThread.Start();
// Create a low priority thread that checks and deletes client
// SocktConnection objcts that are marked for deletion.
m_purgingThread = new Thread(new ThreadStart(PurgingThreadStart));
m_purgingThread.Priority=ThreadPriority.Lowest;
m_purgingThread.Start();
}
}
for each socket that it will be listening by a TCPListener.
private void ServerThreadStart()
{
// Client Socket variable;
Socket clientSocket = null;
TCPSocketListener socketListener = null;
while(!m_stopServer)
{
try
{
// Wait for any client requests and if there is any
// request from any client accept it (Wait indefinitely).
clientSocket = m_server.AcceptSocket();
// Create a SocketListener object for the client.
socketListener = new TCPSocketListener(clientSocket);
// Add the socket listener to an array list in a thread
// safe fashon.
//Monitor.Enter(m_socketListenersList);
lock(m_socketListenersList)
{
m_socketListenersList.Add(socketListener);
}
//Monitor.Exit(m_socketListenersList);
// Start a communicating with the client in a different
// thread.
socketListener.StartSocketListener();
}
catch (SocketException se)
{
m_stopServer = true;
}
}
}
Here it is the full project article.

Tcp Server/Client Application to communicate with other PCs

i'm trying to make an application which allows the connection between 2 PCs(i planned on making it multi threaded later but lets keep it more simple at the beginning). This could be either used for chatting or sending data to the other pc and he does something to the data and sends it back.
This is my coding so far:
Server:
class Program
{
private static StreamWriter serverStreamWriter;
private static StreamReader serverStreamReader;
private static bool StartServer()
{
//setting up Listener
TcpListener tcpServerListener = new TcpListener(IPAddress.Any, 56765);
tcpServerListener.Start();
Console.WriteLine("Server Started!");
Console.WriteLine("Waiting for Connection...");
Socket serverSocket = tcpServerListener.AcceptSocket();
try
{
if (serverSocket.Connected)
{
Console.WriteLine("Client connected to Server!");
//open network stream on accepted socket
NetworkStream serverSockStream = new NetworkStream(serverSocket);
serverStreamWriter = new StreamWriter(serverSockStream);
serverStreamReader = new StreamReader(serverSockStream);
}
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
return false;
}
return true;
}
static bool once = false;
static void Main(string[] args)
{
//Set Console Window Stuff
Console.Title = "Server";
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Green;
Console.BufferWidth = 120;
Console.Clear();
//Start Server
if (!StartServer())
Console.WriteLine("Error while Starting Server!");
//Waiting till Client sends Something
while (true)
{
string data = "Append Something to Me - ";
if (!once)//that check -.-
{
serverStreamWriter.WriteLine(data);
serverStreamWriter.Flush();
once = true;
}
Console.WriteLine("Client: " + serverStreamReader.ReadLine());
if (serverStreamReader.ReadLine() != data)
{
serverStreamWriter.WriteLine(data);
serverStreamWriter.Flush();
}
}
}
}
Client:
class Program
{
private static StreamReader clientStreamReader;
private static StreamWriter clientStreamWriter;
private static bool ConnectToServer()
{
try
{
TcpClient tcpClient = new TcpClient("127.0.0.1", 56765);
Console.WriteLine("Connected to Server!");
NetworkStream clientSockStream = tcpClient.GetStream();
clientStreamReader = new StreamReader(clientSockStream);
clientStreamWriter = new StreamWriter(clientSockStream);
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
return false;
}
return true;
}
private static void SendToServer(string message)
{
try
{
clientStreamWriter.WriteLine(message);
clientStreamWriter.Flush();
}
catch (Exception se)
{
Console.WriteLine(se.StackTrace);
}
}
static void Main(string[] args)
{
//Set Console Window Stuff
Console.Title = "Client";
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Red;
Console.BufferWidth = 120;
Console.Clear();
if (!ConnectToServer())
Console.WriteLine("Error while Connecting to Server!");
SendToServer("Send Me Data...");
//Waiting till Server sends Something
while (true)
{
string response = clientStreamReader.ReadLine();
Console.WriteLine(response + "|| Appending Text...");
response += "Appended Text!";
Console.WriteLine("Sended " + response + " back to server!");
SendToServer(response);
}
}
}
Even though this isn't really good coding, it works for me, BUT the main problem with this is it only works on my local machine. How would i make it so if i run the server app on my pc and my friend runs the client app on his pc those two connect!? Help would be really great since i wasn't able to found a detailed tutorial or such and i only created this Account to ask for help here :)
TcpClient tcpClient = new TcpClient("localhost", 3333);
Instead of "localhost", use the remote machine's address here.
Edit:
You don't seem to understand how this connection process works, so I'll try to explain it a little better.
Your server is opening up a socket on port 3333, listening for any connections. This process does not need any external IP adress.
You clients are trying to connect to the server. They need to know what server they're connecting to, so you need to supply them with an IP address. An example would be something like
TcpClient tcpClient = new TcpClient("127.0.0.1", 3333);
//this is identical to using "localhost"
There's no way for you to get around at some point using a remote address in the connection protocol. You can't just tell the client "connect on port 3333" and expect it to know exactly where it needs to connect.
The comment explaining how to resolve a local IP address isn't useful in your case, because what you ended up doing was just telling the client to connect to itself, as you resolved the client's IP address and tried to connect to that.
However, you can have multiple clients connect to the same server. In this case you won't need multiple remote IP addresses, you just tell all the clients to connect to the same remote address and then handle that on the server. This is where the RemoteEndPoint comes into effect.
At the server level you can use the RemoteEndPoint to find the IP address of the clients connecting to it, and use this IP address to return information to those clients.
All in all, you WILL have to use some hardcoded address for your initial
TcpClient tcpClient = new TcpClient(address, 3333);
step. There's no way around this.

Java <-> C# Socket: cant receive messages

I need a socket communication between my own written java server and C# client, the problem is that the C# client can't receive any messages from my java server, but sending messages to my java server works.
my workflow:
Java: Create Server
Java: Waiting for Client connection
c#: Create Client
c#: Build connection to the server
c#: send a msg to the server
Java: msg received
java: send msg to c# client
c#: receiving msg from server <- this is the point where the client waits for a message but never get.
Java Server code:
public class Communicator {
private int m_port;
private Socket m_socket;
private ServerSocket m_serverSocket;
public Communicator(int port) {
this.m_port = port;
initConnection();
}
private void initConnection() {
try {
System.out.println("Creating Server");
m_serverSocket = new ServerSocket(m_port);
System.out.println("Waiting for client connection");
m_socket = m_serverSocket.accept();
System.out.println("Connection made");
} catch (IOException e) {
e.printStackTrace();
}
}
public String sendMsg(JSONMessage msg) {
try {
//get msg
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(m_socket.getInputStream()));
System.out.println("Waiting for msg...");
String answer = bufferedReader.readLine();
System.out.println("Received: " + answer);
//send msg
PrintWriter writer = new PrintWriter(m_socket.getOutputStream(),true);
writer.print(msg.getMsg());
System.out.println("Sending: " + msg.getMsg());
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
My C# client code:
class Communicator
{
private int m_port;
private Thread mainThread;
public Communicator(int port)
{
m_port = port;
mainThread = new Thread(new ThreadStart(this.initConnection));
mainThread.Start();
}
public void initConnection()
{
IPEndPoint ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), m_port);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
Console.WriteLine("Trying to build connection");
server.Connect(ip);
Console.WriteLine("Connection successful");
NetworkStream ns = new NetworkStream(server);
StreamReader sr = new StreamReader(ns);
StreamWriter sw = new StreamWriter(ns);
string data;
string welcome = "Hello";
Console.WriteLine("Sending: " + welcome);
sw.WriteLine(welcome);
sw.Flush();
Console.WriteLine("Receiving...");
data = sr.ReadLine();
// --> NEVER REACHING THIS POINT <---
Console.WriteLine("Received: " + data);
}
catch (SocketException e)
{
Console.WriteLine("Connection failed.");
return;
}
}
}
Does somebody has any idea why it never reaches my client code Console.WriteLine("Received: " + data); ?
I already tried with waits on both sides. I'm not getting any exceptions or error so I don't have really an idea where my problem is.
Thanks
If your receiver is expecting lines, your sender has to send lines. Your sender does not send lines, so the receiver waits forever until it gets one.
To avoid these kinds of problems in the future, you should always make a specification document that explains how your protocol works, ideally at the byte level. It should specify whether the protocol contains messages and if so, how the sender marks message boundaries and how the receiver identifies them.
Here, your receiver identifies message boundaries by looking for line endings. But your sender doesn't mark message boundaries with line endings. So the receiver waits forever.
If you had a protocol specification, this would have been obvious. In the future, I strongly urge you to invest the time to specify every protocol you implement.
You need to use println() which adds a new line instead of print(). In Java, readLine waits for a new line and I would expect it to do the same in C#. Also println will auto-flush, so you don't need to flush as well.
If you intend to use this connection mreo than once, you need to keep the BufferedReader and PrintWriter for the connection. (So I suggest you create these after the socket is created/accepted) Creating these multiple times for the same socket can be error prone and confusing.

c# sockets handling multiple clients

I have the following code which I want to implement as my server. As I understand it is async. and should allow connections from multiple clients...
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (true)
{
IAsyncResult res = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
connectionWaitHandle.WaitOne();
}
}
private void HandleAsyncConnection(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
connectionWaitHandle.Set();
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
I have a test app which simply fires requests to my server. As you can see in the code the server just replies with its date/time. The test app sends say 20 requests which are simply test strings. For each of these requests it opens a socket, sends the data to my server and then closes the socket again.
This works fine with one test app running. However, if I open two test apps the second one cannot connect to the server. I thought because I am handling the request async. and because my test app opens then closes the socket before each call I could handle requests from multiple clients?
Edit
If using >=.Net4.5, it's better to use the new network methods that then permit the adoption of async and await. As such, it might be better to follow the example I provided in this post as a starting point.
Original Post
The following code demonstrates how to accept multiple clients asynchronously without spinning off a new thread per connection.
private TcpListener listener;
public void Start()
{
listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
StartAccept();
}
private void StartAccept()
{
listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
}
private void HandleAsyncConnection(IAsyncResult res)
{
StartAccept(); //listen for new connections again
TcpClient client = listener.EndAcceptTcpClient(res);
//proceed
}
You can use this pattern for most async operations.
The way you did it, there is no benefit compared to using AcceptTcpClient. Simply loop and create a new thread for each accepted connection:
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (canRun)
{
var client = listener.AcceptTcpClient();
new Thread(ClientThread).Start(client);
}
}
private void ClientThread(IAsyncResult res)
{
TcpClient client = (TcpClient)res.AsyncState;
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
A golden rule when using asynchronous methods is to NOT block the operation. Blocking would defeat the purpose of using async ops.
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
listener.BeginAcceptTcpClient(OnAccept, listener);
}
private void OnAccept(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}

Categories