Send objects over TCP with multiple clients and one server - c#

Okay, I've been looking around and have found tutorials on both sending custom objects over TCP and also connecting multiple clients to one server, however I haven't been able to find an example of both so have decided to try it myself however I'm stuck. I so far have written a server that can handle an unlimited number of clients but have failed to implement sending of objects. This is the code I have so far for sending custom objects:
Client code:
Person p = new Person("Tyler", "Durden", 30); // create my serializable object
string serverIp = "127.0.0.1";
TcpClient client = new TcpClient(serverIp, 9050); // have my connection established with a Tcp Server
IFormatter formatter = new BinaryFormatter(); // the formatter that will serialize my object on my stream
NetworkStream strm = client.GetStream(); // the stream
formatter.Serialize(strm, p); // the serialization process
strm.Close();
client.Close();
Server code:
TcpListener server = new TcpListener(9050);
server.Start();
TcpClient client = server.AcceptTcpClient();
NetworkStream strm = client.GetStream();
IFormatter formatter = new BinaryFormatter();
Person p = (Person)formatter.Deserialize(strm); // you have to cast the deserialized object
strm.Close();
client.Close();
server.Stop();
This is the code I currently have for multiple clients:
Server code:
private ArrayList m_aryClients = new ArrayList(); //List of connected clients (Used for threading)
public Program()
{
//Empty constructor
}
static Program()
{
}
#region Main Enty Point
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
//Set log file location
setLogFileLocation("/usr/local/bin/ClipCloud/" + DateTime.Now.ToShortDateString() + ".log");
//Start the application
printAndLog("Starting server");
Program appmain = new Program();
//Get local hostname
IPAddress[] addressList = null;
string hostName = "";
try
{
hostName = Dns.GetHostName();
addressList = Dns.GetHostByName(hostName).AddressList;
}
catch (Exception ex)
{
printAndLog("Failed to get local address (" + ex.Message + ")", 1);
}
//Start listening and set up threads
if ((addressList == null ? false : (int)addressList.Length >= 1))
{
object[] objArray = new object[] { "Listening on : (", hostName, ") ", addressList[0], ",", 399 };
printAndLog(string.Concat(objArray), 0);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(addressList[0], 399));
socket.Listen(10);
socket.BeginAccept(new AsyncCallback(appmain.OnConnectRequest), socket);
//Wait until user types exit
while (!(Console.ReadLine().ToLower() == "exit"))
{}
printAndLog("Shutting down server");
socket.Close();
//Clean up after yourself
GC.Collect();
GC.WaitForPendingFinalizers();
printAndLog("Application successfully shutdown");
}
else
{
printAndLog("Unable to obtain local address" , 2);
}
}
#endregion
#region Server requests
public void NewConnection(Socket sockClient)
{
//new client connected
ClientHandler clientHandler = new ClientHandler(sockClient);
m_aryClients.Add(clientHandler);
printAndLog(string.Concat("Client (",clientHandler.Sock.RemoteEndPoint, ") connected"));
//Send client welcome message
DateTime now = DateTime.Now;
string str = string.Concat("{", now.ToString("G"), "}");
byte[] bytes = Encoding.ASCII.GetBytes(str.ToCharArray());
clientHandler.Sock.Send(bytes, (int)bytes.Length, SocketFlags.None);
clientHandler.SetupRecieveCallback(this);
}
public void OnConnectRequest(IAsyncResult ar)
{
try
{
Socket asyncState = (Socket)ar.AsyncState;
NewConnection(asyncState.EndAccept(ar));
asyncState.BeginAccept(new AsyncCallback(OnConnectRequest), asyncState);
}
catch (Exception ex)
{
printAndLog(ex.Message);
}
}
public void OnRecievedData(IAsyncResult ar)
{
ClientHandler asyncState = (ClientHandler)ar.AsyncState;
byte[] recievedData = asyncState.GetRecievedData(ar);
if ((int)recievedData.Length >= 1)
{
foreach (ClientHandler mAryClient in this.m_aryClients)
{
try
{
//This is where all data is sent out to all users!
mAryClient.Sock.Send(recievedData);
}
catch
{
printAndLog(string.Concat("Failed to send data to client (", asyncState.Sock.RemoteEndPoint, ")"), 2);
mAryClient.Sock.Close();
this.m_aryClients.Remove(asyncState);
return;
}
}
asyncState.SetupRecieveCallback(this);
}
else
{
printAndLog(string.Concat("Client (", asyncState.Sock.RemoteEndPoint, ") disconnected"), 0);
asyncState.Sock.Close();
this.m_aryClients.Remove(asyncState);
}
}
#endregion
}
internal class ClientHandler
{
private Socket m_sock;
private byte[] m_byBuff = new byte[50];
public Socket Sock
{
get
{
return this.m_sock;
}
}
public ClientHandler(Socket sock)
{
this.m_sock = sock;
}
public byte[] GetRecievedData(IAsyncResult ar)
{
int num = 0;
try
{
num = this.m_sock.EndReceive(ar);
}
catch
{
}
byte[] numArray = new byte[num];
Array.Copy(this.m_byBuff, numArray, num);
return numArray;
}
public void SetupRecieveCallback(Program app)
{
try
{
AsyncCallback asyncCallback = new AsyncCallback(app.OnRecievedData);
this.m_sock.BeginReceive(this.m_byBuff, 0, (int)this.m_byBuff.Length, SocketFlags.None, asyncCallback, this);
}
catch (Exception ex)
{
Console.WriteLine("Recieve callback setup failed! {0}", ex.Message);
}
}
}
Can someone please help me connecting the two.

Related

How to manage the messages from the client to server

I have some clients that connect to the server at the same time, and each of them send to server a registration message.
So, the messages collide with previous messages when they come to the server.
How can I manage the communications without collision between the messages?
I use asynchronous tcp socket in C#.
Here the server:
class ServerSocket
{
//The ClientInfo structure holds the required information about every
//client connected to the server
struct ClientInfo
{
public Socket socket; //Socket of the client
public string strName; //Name by which the user logged into the chat room
}
//The collection of all clients logged into the room (an array of type ClientInfo)
ArrayList clientList;
//The main socket on which the server listens to the clients
Socket serverSocket;
byte[] byteData = new byte[5000];
const int NUM_CLIENT = 12;
public ServerSocket()
{
clientList = new ArrayList();
}
public void LoadServer()
{
try
{
//We are using TCP sockets
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//Assign the any IP of the machine and listen on port number 1000
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 1000);
//Bind and listen on the given address
serverSocket.Bind(ipEndPoint);
serverSocket.Listen(NUM_CLIENT);
//Accept the incoming clients
serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
Console.WriteLine("###################### S E R V E R ######################");
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void OnAccept(IAsyncResult ar)
{
try
{
Socket clientSocket = serverSocket.EndAccept(ar);
//Start listening for more clients
serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
//Once the client connects then start receiving the commands from her
clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void OnReceive(IAsyncResult ar)
{
string msgReceived = "";
try
{
Socket clientSocket = (Socket)ar.AsyncState;
clientSocket.EndReceive(ar);
msgReceived = GetString(byteData);
string strTemp = "";
for (int i = 0; i < msgReceived.IndexOf("<END>"); i++)
{
strTemp += msgReceived[i];
}
msgReceived = strTemp;
XmlBaseClientMsg xmlBaseClientMsg = new XmlBaseClientMsg();
BaseClientMsg baseClientMsgReceived = new BaseClientMsg();
baseClientMsgReceived = xmlBaseClientMsg.DeserializeFromString(msgReceived);
switch (baseClientMsgReceived.m_messageType)
{
case ClientMsgType.AI_REGISTRATION:
//When a user logs in to the server then we add him to our list of clients
ClientInfo AIClientInfo = new ClientInfo();
AIClientInfo.socket = clientSocket; // save the socket
AIClientInfo.strName = baseClientMsgReceived.m_sSenderID; // save the name of sender client
clientList.Add(AIClientInfo);
Console.WriteLine("The client: " + AIClientInfo.strName + " registered");
break;
case ClientMsgType.ENTITY_REGISTRATION:
//When a user logs in to the server then we add him to our list of clients
ClientInfo EntityClientInfo = new ClientInfo();
EntityClientInfo.socket = clientSocket; // save the socket
EntityClientInfo.strName = baseClientMsgReceived.m_sSenderID; // save the name of sender client
clientList.Add(EntityClientInfo);
Console.WriteLine("The client: " + EntityClientInfo.strName + " registered");
break;
#region
//case Command.Logout:
// //When a user wants to log out of the server then we search for her
// //in the list of clients and close the corresponding connection
// int nIndex = 0;
// foreach (ClientInfo client in clientList)
// {
// if (client.socket == clientSocket)
// {
// clientList.RemoveAt(nIndex);
// break;
// }
// ++nIndex;
// }
// clientSocket.Close();
// break;
#endregion
}
if (baseClientMsgReceived.m_messageType != ClientMsgType.AI_REGISTRATION)
{
Console.WriteLine("Type message: " + baseClientMsgReceived.m_messageType + " To: " +
baseClientMsgReceived.m_sReceiverID + " From: " + baseClientMsgReceived.m_sSenderID);
foreach (ClientInfo clientInfo in clientList)
{
if (clientInfo.strName == baseClientMsgReceived.m_sReceiverID)
{
byte[] message;
message = GetBytes(msgReceived);
// Send the message to reciever client
clientInfo.socket.BeginSend(message, 0, message.Length, SocketFlags.None,
new AsyncCallback(OnSend), clientInfo.socket);
Console.WriteLine("Msg No : " + baseClientMsgReceived.m_nMessageID + " Type: " + baseClientMsgReceived.m_messageType + " ==> has been sent");
break;
}
}
}
////If the user disconnects so no need to listen to him
// if (baseClientMsgReceived.m_messageType != ClientMsgType.Logout)
//{
//Start listening to the message send by the user
clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket);
//}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void OnSend(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndSend(ar);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
}
class Program
{
public static int Main( String[] args )
{
ServerSocket serverSocket = new ServerSocket();
serverSocket.LoadServer();
while(true)
{
Console.ReadLine();
}
}
}
}

C# HTTPS Proxy using TCP

I am trying to implement a HTTPS proxy using C#. The proxy should only support HTTPS, not HTTP. As far as I know, a HTTPListener is not a good choice, as you need a SSL certificate for it to support HTTPS, which a proxy usually does not provide.
I am using a TcpListener and TcpClients. Here's the code I got so far:
protected void HandleTCPRequest(object clientObject)
{
TcpClient inClient = clientObject as TcpClient;
TcpClient outClient = null;
try
{
NetworkStream clientStream = inClient.GetStream();
StreamReader clientReader = new StreamReader(clientStream);
StreamWriter clientWriter = new StreamWriter(clientStream);
// Read initial request.
List<String> connectRequest = new List<string>();
string line;
while (!String.IsNullOrEmpty(line = clientReader.ReadLine()))
{
connectRequest.Add(line);
}
if (connectRequest.Count == 0)
{
return;
}
string[] requestLine0Split = connectRequest[0].Split(' ');
if (requestLine0Split.Length < 3)
{
return;
}
// Check if it is CONNECT
string method = requestLine0Split[0];
if (!method.Equals("CONNECT"))
{
return;
}
// Get host and port
string requestUri = requestLine0Split[1];
string[] uriSplit = requestUri.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (uriSplit.Length < 2)
{
return;
}
string host = uriSplit[0];
int port = Int32.Parse(uriSplit[1]);
// Connect to server
outClient = new TcpClient(host, port);
NetworkStream serverStream = outClient.GetStream();
StreamWriter serverWriter = new StreamWriter(serverStream);
StreamReader serverReader = new StreamReader(serverStream);
// Send 200 Connection Established to Client
clientWriter.WriteLine("HTTP/1.0 200 Connection established\r\n\r\n");
clientWriter.Flush();
Logger.Debug("Established TCP connection for " + host);
while (true)
{
line = clientReader.ReadLine();
if (line != null)
{
Logger.Debug("->Server: " + line);
serverWriter.WriteLine(line);
}
line = serverReader.ReadLine();
if (line != null)
{
Logger.Debug("->Client: " + line);
clientWriter.WriteLine(line);
}
}
}
catch(Exception)
{
// Disconnent if connections still alive
try
{
if (inClient.Connected)
{
inClient.Close();
}
if (outClient != null && outClient.Connected)
{
outClient.Close();
}
}
catch (Exception e)
{
Logger.Warn("Could not close the tcp connection: ", e);
}
}
}
The incoming connections are accepted in another method.
EDIT: I made some changes. Now, the client starts sending SSL data, but the server never responds. After some time, the client just opens a new connection and tries again. The output I get:
Established TCP connection for www.google.de
->Server: ▬♥☺ ?☺ ?♥☺R'"??????#☼}~??♣|]?
->Server: ??_5OL(?? H ??
->Server: ?¶ ? ? 9 8?☼?♣ ? 5?? ?◄?‼ E D 3 2?♀?♫?☻?♦ ? A ♣ ♦ /?↕ ▬ ‼?
->Server: ?♥??
->Server: ☺ 0 ↕ ►
->Server: www.google.de
->Server: ♠ ↨ ↑ ↓ ♂ ☻☺ # 3t
I'm open for other suggestions than a TCP listener. Thanks!
Got it working. Dealing with the SSL data with StreamReader/StreamWriter was wrong. The data was converted to strings and thereby errors appeard (I assume). Using the NetworkStream.Read andNetworkStream.Write methods with byte[] did it.
Here's the code:
/// <summary>
/// Handles a TCP request.
/// </summary>
/// <param name="clientObject">The tcp client from the accepted connection.</param>
protected void HandleTCPRequest(object clientObject)
{
TcpClient inClient = clientObject as TcpClient;
TcpClient outClient = null;
try
{
NetworkStream clientStream = inClient.GetStream();
StreamReader clientReader = new StreamReader(clientStream);
StreamWriter clientWriter = new StreamWriter(clientStream);
// Read initial request.
List<String> connectRequest = new List<string>();
string line;
while (!String.IsNullOrEmpty(line = clientReader.ReadLine()))
{
connectRequest.Add(line);
}
if (connectRequest.Count == 0)
{
throw new Exception();
}
string[] requestLine0Split = connectRequest[0].Split(' ');
if (requestLine0Split.Length < 3)
{
throw new Exception();
}
// Check if it is CONNECT
string method = requestLine0Split[0];
if (!method.Equals("CONNECT"))
{
throw new Exception();
}
// Get host and port
string requestUri = requestLine0Split[1];
string[] uriSplit = requestUri.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (uriSplit.Length < 2)
{
throw new Exception();
}
string host = uriSplit[0];
int port = Int32.Parse(uriSplit[1]);
// Connect to server
outClient = new TcpClient(host, port);
// Send 200 Connection Established to Client
clientWriter.WriteLine("HTTP/1.0 200 Connection established\r\n\r\n");
clientWriter.Flush();
Logger.Debug("Established TCP connection for " + host + ":" + port);
Thread clientThread = new Thread(() => TunnelTCP(inClient, outClient));
Thread serverThread = new Thread(() => TunnelTCP(outClient, inClient));
clientThread.Start();
serverThread.Start();
}
catch(Exception)
{
// Disconnent if connections still alive
Logger.Debug("Closing TCP connection.");
try
{
if (inClient.Connected)
{
inClient.Close();
}
if (outClient != null && outClient.Connected)
{
outClient.Close();
}
}
catch (Exception e)
{
Logger.Warn("Could not close the tcp connection: ", e);
}
}
}
/// <summary>
/// Tunnels a TCP connection.
/// </summary>
/// <param name="inClient">The client to read from.</param>
/// <param name="outClient">The client to write to.</param>
public void TunnelTCP(TcpClient inClient, TcpClient outClient)
{
NetworkStream inStream = inClient.GetStream();
NetworkStream outStream = outClient.GetStream();
byte[] buffer = new byte[1024];
int read;
try
{
while (inClient.Connected && outClient.Connected)
{
if (inStream.DataAvailable && (read = inStream.Read(buffer, 0, buffer.Length)) != 0)
{
outStream.Write(buffer, 0, read);
}
}
}
catch (Exception e)
{
Logger.Debug("TCP connection error: ", e);
}
finally
{
Logger.Debug("Closing TCP connection.");
// Disconnent if connections still alive
try
{
if (inClient.Connected)
{
inClient.Close();
}
if (outClient.Connected)
{
outClient.Close();
}
}
catch (Exception e1)
{
Logger.Warn("Could not close the tcp connection: ", e1);
}
}
}

Memory Leak in C# Socket application

I am trying to write an Server application which is listening on a particular port and waiting for devices to hit that port.Device connects every 30 seconds Once a device connects the device sends its MAC address. But the problem is the memory keeps on increasing and never frees up.
class Server
{
Object threadLock = new Object();
bool stopListening = false;
Socket clientSocket = null;
private void StartDeviceListener()
{
try
{
// create the socket
clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
// bind the listening socket to the port
IPEndPoint ep1 = new IPEndPoint(IPAddress.Any, 60000);
clientSocket.LingerState = new LingerOption(false, 0);
clientSocket.Bind(ep1);
clientSocket.Listen(10); //Waiting for Devices to connect.
do
{
// start listening
Console.WriteLine("Waiting for device connection on {0}....", 60000);
Socket deviceSocket = clientSocket.Accept();
//Console.WriteLine(deviceSocket.
#region ThreadPool
// ThreadPool.QueueUserWorkItem(ProcessRequest, (Object)deviceSocket);
Thread ts = new Thread(ProcessRequest);
ts.IsBackground = true;
ts.Start((Object)deviceSocket);
ts.Join();
#endregion
} while (!stopListening);
}
catch (Exception ex)
{
Console.WriteLine("exception... : " + ex.Message);
StartDeviceListener();
}
finally
{
if (clientSocket != null) { clientSocket.Close(); clientSocket = null; }
}
}
public void Stop()
{
try
{
stopListening = true;
if (clientSocket != null)
{
clientSocket.Disconnect(false);
clientSocket = null;
}
}
catch (Exception ex)
{
Console.WriteLine("exception : " + ex.Message);
}
}
void ProcessRequest(Object args)
{
using (Socket deviceSocket = args as Socket)
{
try
{
//lock the thread while we are creating the client IO Interface Manager
lock (threadLock)
{
byte[] readBuffer = new byte[1024];
// Read from buffer
int count = deviceSocket.Receive(readBuffer, 0, readBuffer.Length, SocketFlags.None);
String macAddress = "";//mac address sent by the device:
if (count > 0)
{
Encoding encoder = Encoding.ASCII;
int size = 0;
while (count > 0)
{
size += count;
// get string
macAddress += encoder.GetString(readBuffer, 0, count).Trim();
// Read from buffer
count = 0;
}
Console.WriteLine(string.Format("{0} trying to connect....", macAddress));
}
deviceSocket.Close();
readBuffer = null;
}
//threadLock = null;
}
catch (Exception ex)
{
Console.WriteLine("exception : " + ex.Message);
}
}
args = null;
}
public void Start()
{
StartDeviceListener();
}
}`
But the problem is the memory keeps on increasing and never frees up.
That is still a far cry from a memory-leak. You're probably chasing a problem that does not exist.
In the last shot you still have a working set of 10MB, that's practically zero.
When you really want to find/solve memory issues, use a profiler.

Problem with simple tcp\ip client-server

i'm trying to write simple tcp\ip client-server.
here is server code:
internal class Program
{
private const int _localPort = 7777;
private static void Main(string[] args)
{
TcpListener Listener;
Socket ClientSock;
string data;
byte[] cldata = new byte[1024];
Listener = new TcpListener(_localPort);
Listener.Start();
Console.WriteLine("Waiting connections [" + Convert.ToString(_localPort) + "]...");
try
{
ClientSock = Listener.AcceptSocket();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
int i = 0;
if (ClientSock.Connected)
{
while (true)
{
try
{
i = ClientSock.Receive(cldata);
}
catch
{
}
try
{
if (i > 0)
{
data = Encoding.ASCII.GetString(cldata).Trim();
ClientSock.Send(cldata);
}
}
catch
{
ClientSock.Close();
Listener.Stop();
Console.WriteLine(
"Server closing. Reason: client offline. Type EXIT to quit the application.");
}
}
}
}
}
And here is client code:
void Main()
{
string data; // Юзерская дата
byte[] remdata ={ };
TcpClient Client = new TcpClient();
string ip = "127.0.0.1";
int port = 7777;
Console.WriteLine("\r\nConnecting to server...");
try
{
Client.Connect(ip, port);
}
catch
{
Console.WriteLine("Cannot connect to remote host!");
return;
}
Console.Write("done\r\nTo end, type 'END'");
Socket Sock = Client.Client;
while (true)
{
Console.Write("\r\n>");
data = Console.ReadLine();
if (data == "END")
break;
Sock.Send(Encoding.ASCII.GetBytes(data));
Sock.Receive(remdata);
Console.Write("\r\n<" + Encoding.ASCII.GetString(remdata));
}
Sock.Close();
Client.Close();
}
When i'm sending to my server i cannt receive data back answer. Sock.Receive(remdata) returns nothing! Why?
You're trying to receive to an empty buffer. You should allocate the buffer with a sensible size, and then take note of the amount of data received:
byte[] buffer = new byte[1024];
...
int bytesReceived = socket.Receive(buffer);
string text = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
(It's somewhat unconventional to use PascalCase for local variables, by the way. I'd also urge you not to just catch Exception blindly, and not to swallow exceptions without logging them.)

TCP server causes MAX CPU utlization

i write this TCP communication library. the problem is that. when a client connects. the CPU usages boosts to maximum....this causes other application to become slow...
please take a look at the code and correct me where i did wrong..
the main code of my TCP library is
TCP Server Class
public class TCPServerEndPoint : ICommunication
{
private string channelName;
private string localIP;
private int localPort;
private string remoteIP;
private int remotePort;
private TcpListener tcpListenter;
/// <summary>
/// Accept the incomming connection and pass it to a thread to handle communication.
/// </summary>
private TCPServerWorker worker;
/// <summary>
/// List of threads created for connected clients.
/// </summary>
List<TCPServerWorker> workerThreads;
/// <summary>
/// Thread to keep listening process in seperate thread.
/// </summary>
private Thread serverThread;
/// <summary>
/// Flag to keep status of Endpoint.
/// </summary>
private bool keepRunning;
public TCPServerEndPoint()
{
this.keepRunning = false;
Guid guid = Guid.NewGuid();
channelName = guid.ToString();
workerThreads = new List<TCPServerWorker>();
}
public TCPServerEndPoint(string localIP, int localPort, string remoteIP, int remotePort)
{
this.localIP = localIP;
this.localPort = localPort;
this.remoteIP = remoteIP;
this.remotePort = remotePort;
workerThreads = new List<TCPServerWorker>();
this.keepRunning = false;
}
public event EventHandler<CommEventArgs> OnCommReceive;
public int CommStart()
{
if (this.IsStarted == true)
{
Console.WriteLine("TCP Server is already running");
return -1;
}
serverThread = new Thread(new ThreadStart(StartListening));
serverThread.IsBackground = true;
serverThread.Start();
return 0;
}
private void StartListening()
{
try
{
IPAddress localAddress = IPAddress.Parse(this.localIP);
tcpListenter = new TcpListener(localAddress, this.localPort);
tcpListenter.Start();
Console.WriteLine("TCP Server started");
Console.WriteLine("Server is listening on port : {0}", this.localPort);
this.keepRunning = true;
// look for incomming connections
while (this.keepRunning)
{
// connection received
TcpClient client = tcpListenter.AcceptTcpClient();
// create a new WorkerThread and pass the connected client to handle.
worker = new TCPServerWorker(client);
worker.dataReceived += new EventHandler<CommEventArgs>(worker_dataReceived);
workerThreads.Add(worker);
worker.Start();
}
tcpListenter.Stop();
Console.WriteLine("TCP Server stopped");
this.keepRunning = false;
}
catch
{
return;
}
}
void worker_dataReceived(object sender, CommEventArgs e)
{
if (this.OnCommReceive != null)
{
e.commChannel = this;
this.OnCommReceive(this, e);
}
}
public int CommStop()
{
if (this.IsStarted == false)
return -1;
// Close all worker threads created for connected clients.
foreach (TCPServerWorker item in workerThreads)
{
item.KeepRunning = false;
}
// break the listening loop
this.keepRunning = false;
// clear the worker thread list
workerThreads.Clear();
// force server to receive message to break while(keepRunning) loop
byte[] data = new byte[4];
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(this.localIP), localPort);
Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
tcpClient.Connect(ipEndPoint);
tcpClient.SendTo(data, ipEndPoint);
tcpClient.Close();
return 0;
}
public int CommSend(CommEventArgs obj)
{
obj.destAddress = this.remoteIP;
obj.destPort = this.remotePort;
return CommSendTo(obj);
}
public int CommSendTo(CommEventArgs obj)
{
int n;
byte[] buf;
try
{
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(obj.destAddress), obj.destPort);
buf = (byte[])obj.data;
Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
tcpClient.Connect(ipEndPoint);
n = tcpClient.SendTo(buf, ipEndPoint);
tcpClient.Close();
}
catch (Exception ex)
{
Console.WriteLine("Exception :: {0}", ex.Message);
return -1;
}
if (n == buf.Length)
{
if (OnCommSendComplete != null)
{
OnCommSendComplete(this, obj);
}
Console.WriteLine("Sent {0} bytes to {1}:{2}", n, obj.destAddress, obj.destPort);
}
else
{
return -1;
}
return n;
}
}
}
TCPServerWorker.cs
class TCPServerWorker
{
private TcpClient client;
private bool keepRunning;
public event EventHandler<CommEventArgs> dataReceived;
private const int MAX_TCP_DATA = 64000;
public bool KeepRunning
{
get
{
return this.keepRunning;
}
set
{
this.keepRunning = value;
}
}
public TCPServerWorker(TcpClient client)
{
this.client = client;
this.keepRunning = false;
}
public void Start()
{
Thread thread = new Thread(new ThreadStart(Process));
thread.IsBackground = true;
thread.Start();
}
private void Process()
{
if (client.Connected == true)
{
Console.WriteLine("Client connected :: {0}", client.Client.RemoteEndPoint);
this.keepRunning = true;
while (this.keepRunning)
{
// in my view. here is the main problem. this loop run for infinite time and causes CPU to reach at 100
byte[] buffer = new byte[MAX_TCP_DATA];
NetworkStream stream = client.GetStream();
StreamWriter writer = new StreamWriter(client.GetStream());
if (stream.DataAvailable == true)
{
int receivedBytesCount = stream.Read(buffer, 0, buffer.Length);
byte[] receivedBuffer = new byte[receivedBytesCount];
Array.Copy(buffer, receivedBuffer, receivedBytesCount);
String msg = Encoding.UTF8.GetString(receivedBuffer);
Console.WriteLine("Received MSG ::: " + msg);
writer.WriteLine("Server : Received {0} bytes", receivedBytesCount);
CommEventArgs comEventArg = new CommEventArgs();
comEventArg.data = (byte[])receivedBuffer;
IPEndPoint remoteIPEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;
comEventArg.srcAddress = remoteIPEndPoint.Address.ToString();
comEventArg.srcPort = remoteIPEndPoint.Port;
comEventArg.length = receivedBytesCount;
this.OnDataReceived(comEventArg);
writer.Flush();
}
}
client.Close();
}
}
protected void OnDataReceived(CommEventArgs e)
{
if (this.dataReceived != null)
{
this.dataReceived(this, e);
}
}
}
}
You're using nonblocking I/O which leads to a loop (at least) in your client
while (this.keepRunning) {...}
which is consuming all your CPU resources by busy waiting.
You should consider to use blocking I/O or Socket.Select
Look at the first remark here
Details about select
One thing to note is that you never SET IsStarted .. you only GET it ._. Maybe you're spawning hundreds of threads =/ I'm talking about the TCPServerEndPoint class =/
Yes, you are busy waiting for a connection. I don't know socket programming so I can't give you details, but what you need to do is wait for a connection using the blocking system call.
I solved the issue after modifying the Process method of TCPServerWorker.cs
here is the changes
private void Process()
{
if (client.Connected == true)
{
Console.WriteLine("Client connected :: {0}", client.Client.RemoteEndPoint);
Byte[] bytes = new Byte[MAX_TCP_DATA];
String data = null;
NetworkStream stream = client.GetStream();
int i;
try
{
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// bytes contains received data in byte[].
// Translate data bytes to a UTF-8 string.
byte[] receivedBuffer = new byte[i];
Array.Copy(bytes, receivedBuffer, i);
data = System.Text.Encoding.UTF8.GetString(receivedBuffer);
Console.WriteLine("Received MSG ::: " + data);
// Process the data sent by the client.
byte[] msg = System.Text.Encoding.UTF8.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
CommEventArgs comEventArg = new CommEventArgs();
comEventArg.data = receivedBuffer;
IPEndPoint remoteIPEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;
comEventArg.srcAddress = remoteIPEndPoint.Address.ToString();
comEventArg.srcPort = remoteIPEndPoint.Port;
comEventArg.length = i;
this.OnDataReceived(comEventArg);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception : " + ex.Message);
}
finally
{
client.Close();
}
}
}

Categories