Socket read freezes - c#

I'm working on small program for learning purpose.
My program is simple Telnet console.
Using visual studio 2010 Express I created pretty cool UI now I'm trying to establish communication with remote server(Creston control processor). I copied and pasted class from this Microsoft article and when I execute the class the program freezes. I'm not sure how to properly describe what happens but in basic word all controls(including close button) stop working.
Here code for my class:(I added few debug lines);
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
public string TempString = string.Empty;
public int TotalBytesRead = 0;
public char[] charBuffer = new char[1000];
}
public class AsynchronousClient
{
// The port number for the remote device.
private const int port = 23;
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
private static String response = String.Empty;
public AsynchronousClient()
{
}
public void New()
{
StartClient();
}
private static void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("10.106.6.60"), port);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
Console.WriteLine("StartSend");
// Send test data to the remote device.
//Send(client, "hostname\n");
//sendDone.WaitOne();
Console.WriteLine("WaitForResponse");
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Read From Socket : {0}", response);
Console.WriteLine("ReleaseSocket");
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Disconnect(true);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Receive(Socket client)
{
try
{
// Create the state object.
Console.WriteLine("Receive");
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
Console.WriteLine("Start Read");
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
Console.WriteLine("Bytes read: {0}", bytesRead);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
string tsTempString = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
state.TempString += tsTempString;
Console.WriteLine("String {0}", tsTempString);
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Send(Socket client, String data)
{
Console.WriteLine("Send");
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Console.WriteLine("SendCallBack");
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
When connecting to the server it responds with following lines:
CP3 Console
Warning: Another console session is open
CP3>
When I run the program i get following output:
Socket connected to 10.106.6.60:23
StartSend
WaitForResponse
Receive
Start Read
Bytes read: 13
String CP3 Console
Start Read
Bytes read: 43
String Warning: Another console session is open
Start Read
Bytes read: 6
String
CP3>
The thread '<No Name>' (0x1d80) has exited with code 0 (0x0).
The thread '<No Name>' (0x24bc) has exited with code 0 (0x0).
I tried different methods of reading stream but no successes. The program still hangs up at the same spot.
It seems as after reading last byte ">" the program does not re-executes method "ReceiveCallback" to exit out of the loop.
I get feeling it has something with the way "ReceiveCallback" is being called but I could not figure out what client.beginReceive() parameters actually do.

To expand on Roemer's answer: EndReceive will return 0 only if the conversation has terminated. That usually means a TCP packet with the FIN or RST flag has been received, most often because the peer - in your case, the server - closed its endpoint or exited. (There are various other cases; for example, a firewall or intermediate node could generate an RST.)
(Roemer wrote "BeginReceive never returns zero...", but clearly meant EndReceive, since BeginReceive returns the IAsyncResult object.)
If the peer doesn't close its end of the conversation, EndReceive won't return 0, and you'll never enter the else branch of your callback that invokes receiveDone.Set().
It's not entirely clear from your description exactly how the server behaves, but its last send of 6 bytes was clearly a newline followed by the "CP3>" prompt. At that point it's waiting for your client to send something. It's not going to close the connection.
TCP is a bytestream service - it doesn't provide record boundaries. So there's no way for the socket layer to know when the server is "done sending", except when the server closes the connection. You have three choices for your client:
Parse the server's output as you receive it and recognize when it's waiting for input (in this case, that means recognizing the "CP3>" prompt)
Decide the server's done after some arbitrary time has passed with no further data from the server
Don't worry about it, and simply output data from the server as you receive it
That third option is the simplest one. Do your first BeginReceive after making the connection. Then, in your callback method, if the conversation is still open and no errors have occurred, process the data you've received and invoke BeginReceive again.

To be honest, this example from microsoft is really bad.
In general, client.EndReceive never returns 0 except when the connection is closed. So receiveDone.Set will never be called in your example. In a more real-live example, you should check the received data in ReceiveCallback and when a keyword (like "Login: ") occurs, set the receiveDone and start sending (the login data for example) and the start receiving again and so on. You might also want to look at the async/await keyword (.net 4.5) and maybe upgrade to Visual Studio community edition :)
There are tons of examples on codeproject or found via google (like http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx).

Related

Multithreading: passing different custom control properties between threads (or using them asynchronously)

I'm trying to develop a project where I can have multiple clients making their own server requests for the purpose of stress testing. I'm having a lot of difficulty figuring out how I can manipulate custom control properties when I make a new thread and want that thread to do the work. I have upwards of 100 controls; so ideally 100 individual clients. The problem is my controls are part of the GUI and I don't know how to allow that thread in question get access from that relative control.
Here's what I have:
// Custom project.class to get access to a custom base of properties created within the tool itself.
List<custom_control_project.custom_control_widget> controlList = new List<custom_control_project.custom_control_widget>();
private async void btnStart_Click(object sender, EventArgs e)
{
...// control property initializations
foreach (var control in controlList)
{
if (control.Enabled)
{
Thread thread = new Thread(() => StartClient());
thread.Start();
// Loop until worker thread activates.
while (!thread.IsAlive);
... // Ideally the GUI updates would happen from these threads. Simple updates to labels based on status code responses and expected xml parameters received.
}
}
My StartClient() is largely based off Microsofts asynchronous socket client example here: http://msdn.microsoft.com/en-us/library/bew39x2a%28v=vs.110%29.aspx
I was running these clients asynchronously but the program was not my end result. I have made a few changes, including resetting the ManualResetEvents. However, when I run my application, all the controls still run one after the other, and I'd like them to be independent. Do I have the right approach by making new threads with the StartClient()?
Referencing microsofts example, the part I'm most interested in is the ReceiveCallback(IAsyncResult ar) method:
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
// ManualResetEvent instances signal completion.
private ManualResetEvent connectDone =
new ManualResetEvent(false);
private ManualResetEvent sendDone =
new ManualResetEvent(false);
private ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
private String response = String.Empty;
public void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
//IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
//IPAddress ipAddress = ipHostInfo.AddressList[0];
//IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(asyncServerHolder, asyncPortHolder,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
// Send test data to the remote device.
Send(client, (Upload)); //POST HTTP string + xml parameters
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
//MessageBox.Show("Response received : " + response);
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
// Reset all manual events for next instance.
connectDone.Reset();
sendDone.Reset();
receiveDone.Reset();
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
//MessageBox.Show("Socket connected to " + client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response1 = state.sb.ToString();
///
///
/// **THIS IS WHERE I WANT ALL THE PROCESSING TO BE DONE**
/// **AFTER THE RESPONSE IS COMPLETE!!**
///
///
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private void Send(Socket client, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}
private void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
//MessageBox.Show("Sent " + bytesSent + " bytes to server.");
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
How am I able to get the relative control from my foreach statement passed into the method and then amend my GUI (invoking somehow?) based on the outcome? Also, is it even possible to make each client independent, and have multiple client to server to client requests simultaneously? That is my main objective.
If this is a far fetched or very discouraged way of attempting this, please say so. Without diving into too much programming jargon (for understanding purposes, I'm fairly new to programming), how would you go about doing this?
Thanks in advance!
Well, you can sort of manipulate any control from a different thread by using the BeginInvoke function on the control, passing the action you want to execute. The action will be executed on the UI thread.
But your main problem here is that you're failing to separate the concerns. You UI code can for sure make actions happen, but these actions should be distinct from any UI code. You should design your actions in such a way to make them reusable. In other words, if you decide to rewrite your UI from scratch, you should still be able to reuse your actions as-is.
To make this possible, your actions should not reference any UI, they even should not be aware of the existence of any UI. This will make your code more manageable. So extract all that stuff in a different class, and then use something like events for instance to communicate back with the UI. The UI code then would make the BeginInvoke call.

TCP server in C# causing 100% CPU usage after 2-3 days

Here's my code for a very simple TCP Server (basically the sample Asynchronous Server Socket example - http://goo.gl/Ix5C - modified slightly):
public static void InitiateListener()
{
try
{
allDone = new ManualResetEvent(false);
configFile = new XmlConfig();
StartListening();
}
catch (Exception exc)
{
LogsWriter f = new LogsWriter(configFile.ErrorLogsPath);
f.WriteToFile(exc.Message);
f.CloseFile();
}
}
private static void StartListening()
{
try
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, configFile.Port);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception exc)
{
throw exc;
}
}
public static void AcceptCallback(IAsyncResult ar)
{
allDone.Set(); // Signal the main thread to continue.
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
string hexData = string.Empty;
// Retrieve the state object and the handler socket from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
try
{
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
hexData = BitConverter.ToString(state.buffer);
if (hexData.Contains("FA-F8")) //heartbeat - echo the data back to the client.
{
byte[] byteData = state.buffer.Take(bytesRead).ToArray();
handler.Send(byteData);
}
else if (hexData.Contains("0D-0A")) //message
{
state.AsciiData = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
state.ParseMessage(configFile);
}
}
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch (Exception)
{
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
This is all in a Windows service. And the CPU maxes to 100% after about 2 and a half days of running perfectly acceptably. This has happened 3 times now - the windows service always works fine and functions as it's supposed to, utlizing almost no CPU resources but sometime on the 3rd day goes to 100% and stays there until the service is resarted.
I get very simple CSV packets, that I parse quickly and send it off to a database via a webservice in this method:
state.ParseMessage(configFile);
Even when the CPU is 100%, the database gets filled up pretty reliably. But I understand this could be one place where I need to investigate?
Which other areas of the code seem like they could be causing the problem? I'm new to async programming, so I don't know if I need to close threads manually. Also, this might be another problem:
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
Calling that line within ReadCallback itself. I do this to maintain the connection with the client and continue to receive the data, but maybe I should close to the socket and force a new connection?
Could you please offer some suggestions? Thanks
Instead of loop while(true) in startlistening method we need to call
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
from AcceptCallback method once completion of accepting new client.
You need to detect disconnection through bytesRead == 0. Right now you don't and instead issue another read.
Looks like you have copied MSDN sample code. I can tell because of the insightless combination of async IO and events. All this code becomes simpler when you use synchronous IO.

Socket Programming multiple client one server

I am just starting out Socket Programming in C# and am now a bit stuck with this problem.
How do you handle multiple clients on a single server without creating a thread for each client?
The one thread for each client works fine when there are say 10 clients but if the client number goes up to a 1000 clients is creating a thread for every single one of them advisable? If there is any other method to do this can someone please tel me?
Try to use asynchronous server.
The following example program creates a server that receives connection requests from clients. The server is built with an asynchronous socket, so execution of the server application is not suspended while it waits for a connection from a client. The application receives a string from the client, displays the string on the console, and then echoes the string back to the client. The string from the client must contain the string <EOF> to signal the end of the message.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
public class StateObject {
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener {
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener() {
}
public static void StartListening() {
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
// Bind the socket to the local endpoint and listen for incoming connections.
try {
listener.Bind(localEndPoint);
listener.Listen(100);
while (true) {
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener );
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar) {
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar) {
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer,0,bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1) {
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content );
// Echo the data back to the client.
Send(handler, content);
} else {
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
private static void Send(Socket handler, String data) {
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
Socket handler = (Socket) ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args) {
StartListening();
return 0;
}
}
That's will be the best solution.
Threads can work fine but rarely scales well to that many clients. There are two easy ways and lots of more complex ways to handle that, here's some pseudocode for how the easier two are usually structured to give you an overview.
select()
This is a call to check which sockets have new clients or data waiting on them, a typical program looks something like this.
server = socket(), bind(), listen()
while(run)
status = select(server)
if has new client
newclient = server.accept()
handle add client
if has new data
read and handle data
Which means no threads are needed to handle multiple clients, but it doesn't really scale well either if handle data take a long time, then you won't read new data or accept new clients until that's done.
Async sockets
This is another way of handling sockets which is kind of abstracted above select. You just set up callbacks for common events and let the framework do the not-so-heavy lifting.
function handleNewClient() { do stuff and then beginReceive(handleNewData) }
function handleNewData() { do stuff and then beginReceive(handleNewData) }
server = create, bind, listen etc
server.beginAddNewClientHandler(handleNewClient)
server.start()
I think this should scale better if your data handling take a long time. What kind of data handling will you be doing?
This could be a good starting point. If you want to avoid 1 thread <-> 1 client; then you should use async socket facilities provided in .NET. Core object to use here is SocketAsyncEventArgs.

Unable to Read byte Stream in C#

I am building a client server application where a client has to send some byte stream and the server responds to it based on the bytes received from the Client. I am using the NetworkStream.Write and NetworkStream.Read methods to send and receive data. The client is able to create a TCP connection to the server. After accepting the connection, the server does NetworkStream.Read and waits for some input from the client. The Client sends the data using the NetworkStream.Write and also does NetworkStream.Flush. But the Server never wakes up from the Read.
Can you guys suggest me what could be the problem here or if you know any other methods to send Byte Stream over a TCP Connection in C# please let me know.
Thanks!
Smart-ass comments aside: even though you are only interested in 2 lines of code, I'm willing to bet your problem is someplace else in your code.
Using a modified version of the code found here, I constructed a simple example that works in my testing.
public static void Main()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
stream.Read(bytes, 0, bytes.Length);
Console.WriteLine(System.Text.Encoding.ASCII.GetString(bytes));
// Shutdown and end connection
client.Close();
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
The read call will wait and return when I send it 1 byte with another program. We would need to see some code to figure out why this works and yours does not.

Manage several/multiple tcp connections

I have a server application and client application with the functionality already working. Let me show you how I connect my client application to my server app:
//SERVER
// instantiate variables such as tempIp, port etc...
// ...
// ...
server = new TcpListener(tempIp, port); //tempIp is the ip address of the server.
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[MaxChunkSize];
String data = null;
// Enter the listening loop.
while (disconect == false)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
client = server.AcceptTcpClient(); // wait until a client get's connected...
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
stream = client.GetStream();
// now that the connection is established start listening though data
// sent through the stream..
int i;
try
{
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// etc..
....
ok now on the client side lets say I want to establish a connection then send some data through the stream
//Client
client = new TcpClient(serverIP, port);
// Get a client stream for reading and writing.
stream = client.GetStream();
//then if I wish to send the string hello world to the server I would do:
sendString(stream, "Hello world");
protected void sendString(NetworkStream stream, string str)
{
sendBytes(stream, textToBytes(str));
}
protected void sendBytes(NetworkStream stream, Byte[] data)
{
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
}
protected static Byte[] textToBytes(string text)
{
return System.Text.Encoding.ASCII.GetBytes(text);
}
since I am able to send bytes I am able to send files or everything that I want. the technique that I use is that if I send the string file for example to the server then the server will start listening for a file. It will open a stream and write the received bytes to that file. If a different keyword is send the server will start listening on a different method etc..
So when dealing with one server and one client everything works great. Now I want to add more clients and need them to also connect to the server. I know that several connections can be establish on the same port just like we do it with por 80 on websites... I do not know how to manage several connections. so one thing I was thinking was to leave everything as it is. if a connection is established then tell the server to start another thread listening for other connections on the same port. with this technique I will have several threads running plus I just know the basics of multrythreading. If this technique is my best option I will start implementing it. You guys out there are really knowledgeable about all this so it will be nice if someone can point me on the right direction. Or maybe I should listen on several ports. if the server is already connected on port 7777 for example then do not accept connections from that port and start listening on port 7778 for example. I mean there could be so many different ways of achieving what I need and you guys probably know the best way. I just know the basics of networking...
You could use threading:
var client = server.AcceptTcpClient();
var t = new Thread(new ParameterizedThreadStart(AccentClient));
t.Start(client);
The target method would look like this
public void AccentClient(object clientObj)
{
var client = clientObj as TcpClient;
// Do whatever you need to do with the client
}
If you are not familiar with multithreading, it is important you learn at least the basics first.
You could implement a class that encapsulates TCP behavior. Check this class:
public class SimpleListener
{
private System.Net.Sockets.TcpListener _tcpListen;
//declare delegate to handle new connections
public delegate void _new_client(System.Net.Sockets.TcpClient tcpclient);
//declare a clients container (or something like...). OPTION 1
List<System.Net.Sockets.TcpClient> _connected_clients;
//declare an event and event handler (the same for _new_client) for new connections OPTION 2
public event _new_client new_tcp_client;
//public (The list of connected clients).
public List<System.Net.Sockets.TcpClient> ConnectedClients { get { return _connected_clients; } }
public SimpleListener(string ip, int listenport)
{
System.Net.IPAddress ipAd = System.Net.IPAddress.Parse(ip);
_tcpListen = new System.Net.Sockets.TcpListener(new System.Net.IPEndPoint(ipAd,listenport));
_connected_clients = new List<System.Net.Sockets.TcpClient>();
}
//Fire this method to start listening...
public void Listen()
{
_tcpListen.Start();
_set_listen();
}
//... and this method to stop listener and release resources on listener
public void Stop()
{
_tcpListen.Stop();
}
//This method set the socket on listening mode...
private void _set_listen()
{
//Let's do it asynchronously - Set the method callback, with the same definition as delegate _new_client
_tcpListen.BeginAcceptTcpClient(new AsyncCallback(_on_new_client), null);
}
//This is the callback for new clients
private void _on_new_client(IAsyncResult _async_client)
{
try
{
//Lets get the new client...
System.Net.Sockets.TcpClient _tcp_cl = _tcpListen.EndAcceptTcpClient(_async_client);
//Push the new client to the list
_connected_clients.Add(_tcp_cl);
//OPTION 2 : Fire new_tcp_client Event - Suscribers will do some stuff...
if (new_tcp_client != null)
{
new_tcp_client(_tcp_cl);
}
//Set socket on listening mode again... (and wait for new connections, while we can manage the new client connection)
_set_listen();
}
catch (Exception ex)
{
//Do something...or not
}
}
}
You could use this in your code:
//SERVER
// instantiate variables such as tempIp, port etc...
// ...
// ...
SimpleListener server = new SimpleListener(tempIp, port); //tempIp is the ip address of the server.
//add handler for new client connections
server.new_tcp_client += server_new_tcp_client;
// Start listening for client requests.
server.Listen();
.... //No need to loop. The new connection is handled on server_new_tcp_client method
void server_new_tcp_client(System.Net.Sockets.TcpClient tcpclient)
{
// Buffer for reading data
Byte[] bytes = new Byte[MaxChunkSize];
String data = null;
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
System.IO.Stream stream = tcpclient.GetStream();
// now that the connection is established start listening though data
// sent through the stream..
int i;
try
{
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// etc..
....
}

Categories

Resources