I'm seeing an issue where I have a UDP client & server exchanging messages frequently and the memory usage for both entities is increasing at a rate of approximately 8K per second (althoughly ultimately, this depends on the rate of commuinications between them) as observed in the Task Manager.
To illustrate this as simply as possible, I've created a sample based upon the MSDN Using UDP Services http://msdn.microsoft.com/en-us/library/tst0kwb1.aspx.
The server:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class UDPListener
{
private const int listenPort = 11000;
private static void StartListener()
{
bool done = false;
UInt32 count = 0;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Loopback, listenPort);
try
{
while (!done)
{
byte[] bytes = listener.Receive(ref groupEP);
if ("last packet" == System.Text.Encoding.UTF8.GetString(bytes))
{
done = true;
Console.WriteLine("Done! - rx packet count: " + Convert.ToString(count));
}
else
{
count++;
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
listener.Close();
}
}
public static int Main()
{
StartListener();
return 0;
}
}
And the client:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace UDPSender
{
class Program
{
static void Main(string[] args)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
IPAddress broadcast = IPAddress.Parse(IPAddress.Loopback.ToString());
byte[] sendbuf = Encoding.ASCII.GetBytes("test string");
IPEndPoint ep = new IPEndPoint(broadcast, 11000);
for (int i = 0; i < 500; i++)
{
s.SendTo(sendbuf, ep);
System.Threading.Thread.Sleep(50);
}
s.SendTo(Encoding.ASCII.GetBytes("last packet"), ep);
s.Dispose();
}
}
}
I've tried both using the Socket interface directly and UDPClient, dropping the client socket after each transmission, explicit GC.Collect etc. to no avail.
Any ideas what's going on here - I can't belive this is a fundamental issue with .NET, there must be an issue with my code/the sample....
Try this :
bytes = null;
Related
I'm having a hard time naming this question and solving my problem.
I'm challenging myself in creating a chat server with multiple chat clients.
I've created a server that instantiates a new ClientManager object upon receiving a new connection via TCP. I'm missing various bits of management currently so ignore that as I'm focusing on figuring this bit out first:
Once the connection is established the ClientManager creates a new background worker for receiving streams. What I'm having trouble is once the stream is read, how can I forward that information back to my main server class to distribute amounts to the other clients (chat clients).
Once again, I'm missing a few management options such as threading, semaphores, etc but that will come as I build it out.
Here is how my server established a connection:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.ComponentModel;
namespace ChatServer
{
class Program
{
private IPAddress localAddr;
private int serverPort;
private BackgroundWorker bwListener;
private List<ClientManager> clients;
private TcpListener server;
static void Main(string[] args)
{
Program progInstance = new Program();
progInstance.clients = new List<ClientManager>();
progInstance.server = null;
try
{
// Set the TcpListener on port 13000.
progInstance.serverPort = 13000;
progInstance.localAddr = IPAddress.Parse("127.0.0.1");
// Start to listen
progInstance.bwListener = new BackgroundWorker();
progInstance.bwListener.WorkerSupportsCancellation = true;
progInstance.bwListener.DoWork += new DoWorkEventHandler(progInstance.ServerListen);
progInstance.bwListener.RunWorkerAsync();
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
//progInstance.server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
private void ServerListen(object sender, DoWorkEventArgs e) {
this.server = new TcpListener(this.localAddr, this.serverPort);
this.server.Start();
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... \n");
Socket client = server.AcceptSocket();
this.AcceptClientConnection(client);
}
}
private void AcceptClientConnection(Socket client) {
ClientManager newClient = new ClientManager(client);
this.clients.Add(newClient);
}
private void DisplayClientConnections() {
}
}
}
And this is the ClientManager
using System;
using System.Net.Sockets;
using System.ComponentModel;
namespace ChatServer
{
class ClientManager
{
NetworkStream stream;
private Socket socket;
private BackgroundWorker bwReceiver;
//data = null;
public ClientManager(Socket socket)
{
this.socket = socket;
this.stream = new NetworkStream(this.socket);
this.bwReceiver = new BackgroundWorker();
this.bwReceiver.DoWork += new DoWorkEventHandler(StartReceive);
this.bwReceiver.RunWorkerAsync();
}
private void StartReceive(object sender, DoWorkEventArgs e) {
String data = null;
Byte[] bytes = new Byte[256];
int i;
while (this.socket.Connected) {
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
}
}
}
}
}
I was thinking that the server should somehow retrieve this information and then write it to the stream, or would I just do that would I just write back to the stream from the ClientManager and then have my actual clients listen and receive? I'm just super lost how to handle this portion of the chat server.
I have been making a C# server and client for a game. I have used many resources to try to create something successful. So far, the client can send stuff to the server and the server can receive them, but I want to be able to send stuff to the client. Also, I don't know what happened, but my server code suddenly stopped printing to console or something. I am new at this and any help is needed. I think I programmed both client and server to be able to send and receive, but something isn't right...
Note: I am using a cmd compiler running an old version of the .NET (but the code still compiles), any help on getting visual studio working to build/compile the code would also be nice :)
Client-side:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
class Program
{
static Boolean done = false;
static void Main(string[] args)
{
Boolean exception_thrown = false;
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
IPAddress send_to_address = IPAddress.Parse("ip-goes-here");
IPEndPoint sending_end_point = new IPEndPoint(send_to_address, 27020);
Console.WriteLine("Enter text to broadcast via UDP.");
Console.WriteLine("Enter a blank line to exit the program.");
Thread listenerT = new Thread(new ThreadStart(Program.listener));
listenerT.Start();
while (!done)
{
Console.WriteLine("Enter text to send, blank line to quit");
string text_to_send = Console.ReadLine();
if (text_to_send.Length == 0)
{
done = true;
listenerT.Abort();
}
else
{
byte[] send_buffer = Encoding.ASCII.GetBytes(text_to_send);
Console.WriteLine("sending to address: {0} port: {1}",
sending_end_point.Address,
sending_end_point.Port);
try
{
sending_socket.SendTo(send_buffer, sending_end_point);
}
catch (Exception send_exception)
{
exception_thrown = true;
Console.WriteLine(" Exception {0}", send_exception.Message);
}
if (exception_thrown == false)
{
Console.WriteLine("Message has been sent to the broadcast address");
}
else
{
exception_thrown = false;
Console.WriteLine("The exception indicates the message was not sent.");
}
}
}
}
static void listener()
{
int listenPort = 27020;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
string received_data;
byte[] receive_byte_array;
try
{
while (!done)
{
Console.WriteLine("Waiting for broadcast");
receive_byte_array = listener.Receive(ref groupEP);
Console.WriteLine("Received a broadcast from {0}", groupEP.ToString());
received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
Console.WriteLine("data follows \n{0}\n\n", received_data);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
Server side:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class UDPListener
{
private const int listenPort = 27020;
//static Boolean done = false;
static IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
static UdpClient udpServer = new UdpClient(27020);
static IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 27020);
static byte[] data = udpServer.Receive(ref remoteEP); // listen on port 11000
static IPAddress send_to_address = IPAddress.Parse("10.240.0.1");
static IPEndPoint sending_end_point = new IPEndPoint(send_to_address, 27020);
public static void Main()
{
Console.WriteLine("Begin listening sequence");
while (true)
{
data = udpServer.Receive(ref groupEP);
Console.WriteLine("Received a broadcast from {0}", groupEP.ToString());
send_to_address = IPAddress.Parse(groupEP.ToString());
Thread listenerT = new Thread(new ThreadStart(UDPListener.sender));
listenerT.Start();
String received_data = Encoding.ASCII.GetString(data, 0, data.Length);
Console.WriteLine(received_data);
}
}
static void sender()
{
while (true)
{
Console.WriteLine("Enter text to send, blank line to quit");
string text_to_send = Console.ReadLine();
if (text_to_send.Length == 0)
{
//done = true;
}
else
{
byte[] send_buffer = Encoding.ASCII.GetBytes(text_to_send);
Console.WriteLine("sending to address: {0} port: {1}",
sending_end_point.Address,
sending_end_point.Port);
udpServer.Send(send_buffer, 0, remoteEP); // reply back
}
}
}
}
Nevermind, a friend of mine figured it out. You can find the final code in a github repo called something like flaming leaf server
I've been playing with some c# socket code that I found at MSDN (original server code and client code) and I've run into a problem that I don't understand. First, here is my socket server code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace AsyncSocketServerTest
{
class Program
{
public class StateObject
{
public Socket socket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public List<byte> bytes = new List<byte>();
}
public static ManualResetEvent allDone = new ManualResetEvent(false);
private const string ipAdd = "127.0.0.1";
public static void StartListening()
{
byte[] bytes = new byte[1024];
IPAddress ipAddress = IPAddress.Parse(ipAdd);
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 25981);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
allDone.Reset();
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.socket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
Console.WriteLine("Inside ReadCallback()...");
// retrieve the state object and the handler socket from the asynchronous state object
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.socket;
// read data from the client socket
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0)
{
// there might be more data, so store the data received so far
for (int bufferIndex = 0; bufferIndex < bytesRead; bufferIndex++)
{
state.bytes.Add(state.buffer[bufferIndex]);
}
socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
else
{
if (state.bytes.Count > 0)
{
// All the data has been read from the client; display it on the console.
byte[] bytesReceived = state.bytes.ToArray();
Console.WriteLine("Received {0} bytes from client...", bytesReceived.Length.ToString());
}
// generate a 50 byte response to send back to the client
Random r = new Random();
byte[] responseToSend = new byte[50];
r.NextBytes(responseToSend);
// *** THIS APPEARS TO BE CAUSING A PROBLEM ***
// send the response back to client
SendBytes(socket, responseToSend);
// ********************************************
// edit - commented out; the socket shouldn't be closed before the response is sent back to the client asynchronously
//socket.Close();
}
}
private static void SendBytes(Socket client, byte[] bytesToSend)
{
client.BeginSend(bytesToSend, 0, bytesToSend.Length, 0, new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
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());
}
}
static void Main(string[] args)
{
StartListening();
Console.ReadKey();
}
}
}
And now for the client code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace AsyncSocketClientTest
{
class Program
{
public class StateObject
{
public Socket socket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public List<byte> bytes = new List<byte>();
}
private const string ipAdd = "127.0.0.1";
// 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);
private static void StartClient()
{
try
{
IPAddress ipAddress = IPAddress.Parse(ipAdd);
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, 25981);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEndPoint, new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
// generate 100 random bytes to send to the server
Random r = new Random();
byte[] buffer = new byte[100];
r.NextBytes(buffer);
// send data to the server
SendBytes(client, buffer);
sendDone.WaitOne();
// *** THIS APPEARS TO BE CAUSING A PROBLEM ***
// receive the response from the remote host
ReceiveBytes(client);
receiveDone.WaitOne();
// ********************************************
// release the socket
client.Shutdown(SocketShutdown.Both);
client.Close();
}
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 (SocketException sockEx)
{
// if the server isn't running, we're going to get a socket exception here...
Console.WriteLine(sockEx.Message);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveBytes(Socket client)
{
Console.WriteLine("Inside ReceiveBytes()...");
try
{
// create the state object
StateObject state = new StateObject();
state.socket = client;
// begin receiving 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)
{
Console.WriteLine("Inside ReceiveCallback()...");
try
{
// Retrieve the state object and the client socket from the asynchronous state object
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.socket;
// Read data from the remote host
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// there might be more data, so store the data received so far
for (int bufferIndex = 0; bufferIndex < bytesRead; bufferIndex++)
{
state.bytes.Add(state.buffer[bufferIndex]);
}
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
if (state.bytes.Count > 0)
{
// All the data has been read from the client; display it on the console.
byte[] bytesReceived = state.bytes.ToArray();
Console.WriteLine("Read {0} bytes from socket...", bytesReceived.Length.ToString());
}
// Signal that all bytes have been received
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void SendBytes(Socket client, byte[] bytesToSend)
{
// Begin sending the data to the remote device
client.BeginSend(bytesToSend, 0, bytesToSend.Length, 0, new AsyncCallback(SendCallback), client);
}
private static 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);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// signal that all bytes have been sent
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
static void Main(string[] args)
{
StartClient();
}
}
}
If I comment out the code in the client that receives the response back from the server as well as the code in the server that attempts to send the response to the client, then things appear to be working as you would expect (i.e., the client connects to the server, sends data and the server receives the data properly). When I uncomment these sections of the code, however, I'm seeing some behavior that I don't understand. In this case, I see the client connect to the server and send data to it. On the server side, the code appears to hang inside ReadCallback(). To better illustrate this, when the code sections I mentioned previously are commented out, I see this:
Client output:
Socket connected to 127.0.0.1:25981
Sent 100 bytes to server.
Server output:
Waiting for a connection...
Waiting for a connection...
Inside ReadCallback()...
Inside ReadCallback()...
Received 100 bytes from client...
As you can see from this output, when the server receives the 100 bytes of client data, I see two calls to ReadCallback(). So now I uncomment the aforementioned code and run it again. This time, I see:
Client output:
Socket connected to 127.0.0.1:25981
Sent 100 bytes to server.
Inside ReceiveBytes()...
Server output:
Waiting for a connection...
Waiting for a connection...
Inside ReadCallback()...
This time, my client sends 100 bytes of data to the server, sets the sendDone ManualResetEvent and then goes into ReceiveBytes(). On the server side, I see a single call to ReadCallback() and nothing else. That leads me to believe that the server didn't properly finish reading the data from the client although I'm not sure why. What am I missing?
This doesn't really answer your exact question but may I suggest an alternate way to go about this? For me threads are a bit easier to understand and the code looks a bit cleaner:
Server
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication2 {
class Program {
static void Main(string[] args) {
ServerWorkThread objThread = new ServerWorkThread();
while(true) {
objThread.HandleConnection(objThread.mySocket.Accept());
}
}
}
public class ServerWorkThread {
public Socket mySocket;
public ServerWorkThread() {
IPEndPoint objEnpoint = new IPEndPoint(IPAddress.Parse("***.***.***.***"), 8888);
mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
mySocket.Bind(objEnpoint);
mySocket.Listen(100);
}
public void HandleConnection(Socket iIncomingSocket) {
Thread worker = new Thread(this.RecieveAndSend);
worker.Start(iIncomingSocket);
worker.Join();
}
public void RecieveAndSend(object iIncoming) {
Socket objSocket = (Socket)iIncoming;
byte[] bytes = new byte[1024];
int bytesRecieved = objSocket.Receive(bytes);
string strReceived = System.Text.Encoding.ASCII.GetString(bytes, 0, bytesRecieved);
Console.WriteLine("Received from client: " + strReceived);
Console.WriteLine("Sending acknowledgement to client");
string strSend = ("Command of: " + strReceived + " was processed successfully");
objSocket.Send(System.Text.Encoding.ASCII.GetBytes(strSend));
objSocket.Close();
}
}
}
Client:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Client {
class Program {
static void Main(string[] args) {
ClientWorkThread thread1 = new ClientWorkThread("I am thread 1");
thread1.SendCommand();
ClientWorkThread thread2 = new ClientWorkThread("I am thread 2");
thread2.SendCommand();
ClientWorkThread thread3 = new ClientWorkThread("I am thread 3");
thread3.SendCommand();
Console.Read();
}
}
public class ClientWorkThread {
private Socket pSocket;
private string command;
public ClientWorkThread(string iCommand) {
IPEndPoint objEnpoint = new IPEndPoint(IPAddress.Parse("***.***.***.***"), 8888);
pSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
pSocket.Connect(objEnpoint);
command = iCommand;
}
public void SendCommand() {
Thread worker = new Thread(this.Send);
worker.Start(pSocket);
}
public void Send(object iSending) {
Socket objSocket = (Socket)iSending;
objSocket.Send(System.Text.Encoding.ASCII.GetBytes(command + " now DO WORK "));
Console.WriteLine("Sending: " + command + " now DO WORK ");
byte[] bytes = new byte[1024];
int bytesRecieved = objSocket.Receive(bytes);
string strReceived = System.Text.Encoding.ASCII.GetString(bytes, 0, bytesRecieved);
Console.WriteLine("Received from server: " + strReceived);
objSocket.Close();
}
}
}
Server output:
Received from client: I am thread 1 now DO WORK
Sending acknowledgement to client
Received from client: I am thread 2 now DO WORK
Sending acknowledgement to client
Received from client: I am thread 3 now DO WORK
Sending acknowledgement to client
Client output:
Sending: I am thread 2 now DO WORK
Sending: I am thread 3 now DO WORK
Received from server: Command of: I am thread 2 now DO WORK was processed successfully
Received from server: Command of: I am thread 3 now DO WORK was processed successfully
Sending: I am thread 1 now DO WORK
Received from server: Command of: I am thread 1 now DO WORK was processed successfully
You could also use thread.Join() to have them finish executing in order.
I'm not sure if the title is all that informative.
I am trying to find/write a socket server that will accept a connection from the client (telnet) and then on behalf of the connected client, connect to one of four telnet servers inside the network.
Once connected I keep a counter of how many connections there are, and then if there are 4 total connections, disallow any new connections until one of the four is available.
I have written this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static int nodeCount = 4;
static int currentNode = 1;
static void Main(string[] args)
{
ServerProgram server = new ServerProgram();
}
class ServerProgram
{
private TcpListener tcpPrimaryListener;
private Thread listenThread;
public ServerProgram()
{
this.tcpPrimaryListener = new TcpListener(IPAddress.Any, 23);
Console.WriteLine("Telnet BBS Port Concentrator Server Started.");
Console.WriteLine("--------------------------------------------");
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpPrimaryListener.Start();
while (true)
{
TcpClient client = this.tcpPrimaryListener.AcceptTcpClient();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private void HandleClientComm(object client)
{
if (currentNode <= nodeCount)
{
Console.WriteLine("Connection thread created.");
StreamWriter swStream;
StreamWriter swStream2;
StreamReader srStream;
StreamReader srStream2;
TcpClient tcpClient = (TcpClient)client;
NetworkStream tcpClientStream = tcpClient.GetStream();
TcpClient telnet = new TcpClient("192.168.100.5" + currentNode, 23);
NetworkStream telnetStream = telnet.GetStream();
currentNode++;
while (true)
{
srStream = new StreamReader(tcpClient.GetStream());
swStream2 = new StreamWriter(tcpClient.GetStream());
srStream2 = new StreamReader(telnet.GetStream());
swStream = new StreamWriter(telnet.GetStream());
swStream.Write(srStream.ReadToEnd());
swStream2.Write(srStream2.ReadToEnd());
}
}
}
}
}
}
I've changed this example multiple times, so I don't really know anymore what I have and have not tried. I'm willing to try anything.
The purpose is actually running this to allow one telnet port open through the firewall, and allowing connections into a small network of DOS machines running telnet fossil driver BBS software. I would just like to redirect telnet traffic to an available system using only one port.
The problem is that I cannot figure out how to actually connect the two sockets together and pass data between them as it happens. The incoming socket and the socket I created on behalf of the server to the server.
Thanks.
UPDATE:
This is what is working for me, I'm still looking over for bugs but it's working so far.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static int nodeCount = 2;
static int currentNode = 1;
static void Main(string[] args)
{
ServerProgram server = new ServerProgram();
}
class ServerProgram
{
private TcpListener tcpPrimaryListener;
private Thread listenThread;
public ServerProgram()
{
this.tcpPrimaryListener = new TcpListener(IPAddress.Any, 23);
Console.WriteLine("Telnet BBS Port Concentrator Server Started.");
Console.WriteLine("--------------------------------------------");
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpPrimaryListener.Start();
while (true)
{
TcpClient client = this.tcpPrimaryListener.AcceptTcpClient();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private void HandleClientComm(object client)
{
string noNodes = "Sorry all nodes are occupied.";
if (currentNode <= nodeCount)
{
Console.WriteLine("Client connected.");
TcpClient tcpClient = (TcpClient)client;
NetworkStream tcpClientStream = tcpClient.GetStream();
TcpClient telnet = new TcpClient("10.24.9.11", 23);
//TcpClient telnet = new TcpClient("192.168.100.5" + currentNode, 23);
NetworkStream telnetStream = telnet.GetStream();
currentNode++;
ByPass linkedSockets = new ByPass(tcpClientStream, telnetStream);
}
else
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream tcpClientStream = tcpClient.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
tcpClientStream.Write(Encoding.ASCII.GetBytes(noNodes), 0, noNodes.Length);
}
}
}
public class ByPass
{
public ByPass(Stream s1, Stream s2)
{
var cTokenSource = new CancellationTokenSource();
var cToken = cTokenSource.Token;
Task.Factory.StartNew(() => Process(s1, s2, cToken, cTokenSource), cToken);
Task.Factory.StartNew(() => Process(s2, s1, cToken, cTokenSource), cToken);
cToken.Register(() => cancelNotification());
}
public void Process(Stream s1, Stream s2, CancellationToken ct, CancellationTokenSource cTokenSource)
{
byte[] buf = new byte[0x10000];
while (true)
{
if (ct.IsCancellationRequested)
{
break;
}
try
{
int len = s1.Read(buf, 0, buf.Length);
s2.Write(buf, 0, len);
}
catch
{
s1.Close(); s2.Close();
cTokenSource.Cancel();
break;
}
}
}
}
static void cancelNotification()
{
Console.WriteLine("Client disconnected.");
currentNode--;
}
}
}
I think, you can create a class similar to below to pass data between two streams
public class ByPass
{
public ByPass(Stream s1, Stream s2)
{
Task.Factory.StartNew(() => Process(s1, s2));
Task.Factory.StartNew(() => Process(s2, s1));
}
public void Process(Stream sIn, Stream sOut)
{
byte[] buf = new byte[0x10000];
while (true)
{
int len = sIn.Read(buf, 0, buf.Length);
sOut.Write(buf, 0, len);
}
}
}
I have made little changes and it works perfect on my side
public class StreamTransmitter
{
static TaskCompletionSource<bool> ts;
public static async Task Start(Stream s1, Stream s2, CancellationToken token)
{
ts = new TaskCompletionSource<bool>();
Process(s1, s2, token);
Process(s2, s1, token);
await ts.Task;
}
private static async Task Process(Stream sIn, Stream sOut, CancellationToken token)
{
byte[] buf = new byte[0x10000];
int len = 0;
do
{
len = await sIn.ReadAsync(buf, 0, buf.Length, token);
await sOut.WriteAsync(buf, 0, len, token);
}
while (len > 0 && !token.IsCancellationRequested);
ts.SetResult(true);
}
}
I'm wondering if my application is getting strings asynchronously if i run it synchronously on other threads?
I don't actually know how to use the BeginSend/BeginReceive, so I used socket.Send(...), socket.Receive(...) on different threads and does that makes my application simulate async connection.
By the way, what happens if the string is bigger than the size of the buffer? For client i used telnet, but telnet actually sends the strings as soon they are get from the keyboard so I can't actually exceed the size of the buffer, but what if I used another client that sends the full string? Is there a way to tell the program that i sent more then the buffer allows it (through my variable recv that is the result of socketReceive)?
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Runtime.Remoting.Messaging;
namespace CSharp_Console_Application
{
class Program
{
delegate Socket GetClients();
static GetClients newClients;
static List<Socket> clients;
static ManualResetEvent allDone = new ManualResetEvent(false);
static void Main(string[] args)
{
IPEndPoint serverIPEP = new IPEndPoint(IPAddress.Any, 9080);
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(serverIPEP);
serverSocket.Listen(10);
Console.WriteLine("Waiting for connections...");
clients = new List<Socket>();
newClients = () =>
{
Socket clientSocket = serverSocket.Accept();
IPEndPoint clientIPEP = (IPEndPoint)clientSocket.RemoteEndPoint;
Console.WriteLine("Connected to {0}.", clientIPEP);
clients.Add(clientSocket);
SendString("Welcome to my server!", clientSocket);
return clientSocket;
};
while (true)
{
allDone.Reset();
newClients.BeginInvoke((itfAR) =>
{
allDone.Set();
AsyncResult ar = (AsyncResult)itfAR;
GetClients invokedDelegate = (GetClients) ar.AsyncDelegate;
Socket clientSocket = invokedDelegate.EndInvoke(itfAR);
IPEndPoint clientIPEP = (IPEndPoint)clientSocket.RemoteEndPoint;
Console.WriteLine("Sent 'Welcome!' to {0}.", clientIPEP);
string currentString = "";
while (true)
{
currentString += ReceiveString(clientSocket);
if (currentString.Contains('\n'))
{
Console.Write(clientIPEP + " said: " + currentString);
List<Socket> clientsWithoutThis = new List<Socket>();
clientsWithoutThis.AddRange(clients);
clientsWithoutThis.Remove(clientSocket);
SendToAll(clientsWithoutThis, currentString);
currentString = "";
}
}
},
null);
allDone.WaitOne();
}
}
static void SendToAll(List<Socket> clients, string message)
{
byte[] data = new byte[1024];
clients.ForEach(clientSocket =>
{
IPEndPoint clientIPEP = (IPEndPoint)clientSocket.RemoteEndPoint;
data = Encoding.ASCII.GetBytes(clientIPEP + " said: " + message + "\r");
clientSocket.Send(data, data.Length, SocketFlags.None);
});
}
static void SendString(string message, Socket clientSocket)
{
byte[] data = new byte[1024];
data = Encoding.ASCII.GetBytes(message + "\n\r");
clientSocket.Send(data, data.Length, SocketFlags.None);
}
static string ReceiveString(Socket clientSocket)
{
byte[] data = new byte[1024];
int recv = clientSocket.Receive(data, data.Length, SocketFlags.None);
if (recv < 1)
return null;
string receivedString = Encoding.ASCII.GetString(data, 0, recv);
return receivedString;
}
}
}
This way your ManualResetEvent is tend to be useless. As soon as you block the main thread, you release in the first line of BeginInvoke with calling the set(). And then you reset it again to set into the waiting state but another BeginInvoke call will unblock the code while the other BeginInvoke may still running. So in the end you will have multiple BeginInvoke thread and eventually you will have multiple exception or out of memory error.