I am trying to get a multi-threaded UDP client/server going, but i'm running into problems on the server side. When a client attempts to register, a thread is created and all the interactions for that client are handled in that thread, but for some reason it only enters the thread once then exits right away.. can anyone help figure out why this happens? -Thanks in advance..
namespace AuctionServer
{
class Program
{
public static Hashtable clientsList = new Hashtable();
static void Main(string[] args)
{
//IPAddress ipAd = IPAddress.Parse("255.255.255.255");
UdpClient server = new UdpClient(8888);
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
string data = "";
int listSize = 0;
Console.WriteLine("Auction Server Started ....");
listSize = clientsList.Count;
while (true)
{
//Reads data
byte[] inStream = server.Receive(ref remoteEndPoint);
data = Encoding.ASCII.GetString(inStream);
//Console.WriteLine("REGISTER " + remoteEndPoint);
if (!data.Contains("DEREGISTER "))
{
byte[] sendBytes = Encoding.ASCII.GetBytes(data + remoteEndPoint.ToString());
server.Send(sendBytes, sendBytes.Length, remoteEndPoint);
handleClinet client = new handleClinet();
Console.WriteLine(data);
clientsList.Add(data, server);
client.startClient(server, data, clientsList, remoteEndPoint);
data = "";
}
}
}
//Broadcast method is used to send message to ALL clients
public static void broadcast(UdpClient dest, string msg, string uName, bool flag, IPEndPoint sendEP, Hashtable clientsList)
{
foreach (DictionaryEntry Item in clientsList)
{
Byte[] broadcastBytes = null;
if (flag == true)
{
broadcastBytes = Encoding.ASCII.GetBytes(msg);
}
else
{
broadcastBytes = Encoding.ASCII.GetBytes(msg);
}
dest.Send(broadcastBytes, broadcastBytes.Length, sendEP);
}
}
}//end Main class
}
namespace AuctionServer
{
public class handleClinet
{
UdpClient clientSocket;
string clNo;
Hashtable clientsList;
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
IPEndPoint myEP = new IPEndPoint(IPAddress.Any, 0);
public void startClient(UdpClient inClientSocket, string clineNo, Hashtable cList, IPEndPoint tempEP)
{
this.myEP = tempEP;
this.clientSocket = inClientSocket;
this.clNo = clineNo;
this.clientsList = cList;
Thread ctThread = new Thread(doChat);
ctThread.Start();
}
private void doChat()
{
int requestCount = 0;
byte[] bytesFrom = new byte[10025];
string dataFromClient = null;
string rCount = null;
requestCount = 0;
while ((true))
{
try
{
//Thread.Sleep(1000);
if (requestCount == 0)
{
Console.WriteLine("Thread Created");
requestCount++;
}
byte[] received = clientSocket.Receive(ref remoteIPEndPoint);
dataFromClient = Encoding.ASCII.GetString(received);
Console.WriteLine(dataFromClient);
if (dataFromClient.Contains("DEREGISTER"))
clientSocket.Send(received, received.Length, remoteIPEndPoint);
//Program.broadcast(clientSocket, "DREG-CONF", clNo, true, myEP, clientsList);
//else
// Program.broadcast(clientSocket, dataFromClient, clNo, true, myEP, clientsList);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadKey();
break;
}
}//end while
}//end doChat
}
The two loops run on different threads. So the loop in Main() is executing concurrently with the loop in your handleClinet class.
If you want to switch to the handleClinet class's loop and debug it, then use the Threads window in the debugger (Debug menu, Windows menu item, then Threads...or press Ctrl-D, T) to switch to that thread. Then you can see the call stack and state of that thread.
Note that this may not work on the Express version of Visual Studio. I haven't tried the most recent version, but past versions did not support the Threads window. (You can still debug a specific thread by setting a breakpoint thereā¦it's just that you can't switch to the thread manually).
Related
I am working on a Master - Slave kind of network relationship between a server and multiple clients.
The server is fine, the problem is that i am new to TCP and do not know how to connect to the server without the client knowing the ip form the start.
If someone could rewrite some of my code so it works, I would be thankful.
The server
namespace Server
{
class Program
{
static void Main(string[] args)
{
TcpListener listen = new TcpListener(IPAddress.Any, 8001);
TcpClient clientSocket = default(TcpClient);
int counter = 0;
listen.Start();
Console.WriteLine(" >> " + "Server Started");
while (true)
{
counter += 1;
clientSocket = listen.AcceptTcpClient();
HandleClinet client = new HandleClinet();
client.startClient(clientSocket, Convert.ToString(counter));
}
}
}
public class HandleClinet
{
TcpClient clientSocket;
string clNo;
public void startClient(TcpClient inClientSocket, string clineNo)
{
clientSocket = inClientSocket;
clNo = clineNo;
Thread ClientThread = new Thread(DoChat);
ClientThread.Start();
}
private void DoChat()
{
byte[] bytesFrom = new byte[1024];
string dataFromClient = null;
byte[] sendBytes = null;
string serverResponse = null;
while ((true))
{
try
{
NetworkStream networkStream = clientSocket.GetStream();
networkStream.Read(bytesFrom, 0, 1024);
dataFromClient = Encoding.ASCII.GetString(bytesFrom);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("\0"));
Console.WriteLine(" >> " + "From client-" + clNo + " " + dataFromClient);
serverResponse = Console.ReadLine();
sendBytes = Encoding.ASCII.GetBytes(serverResponse);
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
}
catch (Exception ex)
{
throw;
}
}
}
}
}
The client
namespace Client
{
class Program
{
public static TcpClient tcpclnt = new TcpClient();
static void Main(string[] args)
{
while(true)
{
LoopConnect();
LoopPacket();
tcpclnt.Close();
}
}
private static void LoopPacket()
{
byte[] bytesFrom = new byte[1024];
string dataFromClient = null;
byte[] sendBytes = null;
string serverResponse = null;
while ((true))
{
try
{
NetworkStream networkStream = tcpclnt.GetStream();
serverResponse = "Give me a command!";
sendBytes = Encoding.ASCII.GetBytes(serverResponse);
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Read(bytesFrom, 0, 1024);
dataFromClient = Encoding.ASCII.GetString(bytesFrom);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("\0"));
Console.WriteLine(" >> " + "From server -" + dataFromClient);
networkStream.Flush();
}
catch (Exception ex)
{
throw;
}
}
}
private static void LoopConnect()
{
Console.WriteLine("Connecting.....");
while(true)
{
try
{
tcpclnt.Connect(IPAddress.Any, 8001); // The problem area
break;
}
catch (Exception)
{
Console.Write(".");
}
}
Console.WriteLine("Connected.");
}
}
}
The client should somehow get address of the server. The method is depending on the network type (local or Internet). In case of Internet it's virtually impossible without some known peer. In case of a local network you could use a broadcast UDP request (this method is depending on the local network routing rules).
I wrote simple Multi-Threaded TCP C# Server program.After I run my program I got high CPU usage and thread count is keep increasing in task manager. Can anyone help me to figure out how to solve and give suggestions?
This is my code.
public class Program
{
static void Main(string[] args)
{
int _Port = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["TCPPort"]);
string _IP = System.Configuration.ConfigurationManager.AppSettings["TCPIP"];
TcpServer server = new TcpServer(_Port);
}
}
public class TcpServer
{
private TcpListener _server;
private Boolean _isRunning;
private static int defaultMax = 8;
public TcpServer(int port)
{
_server = new TcpListener(IPAddress.Any, port);
_server.Start();
_isRunning = true;
LoopClients();
}
public void LoopClients()
{
while (_isRunning)
{
TcpClient newClient = _server.AcceptTcpClient();
SentFirstTimeData_New(newClient);
Thread t = new Thread(new ParameterizedThreadStart(HandleClient));
t.Start(newClient);
}
}
public void HandleClient(object obj)
{
int requestCount = 0;
byte[] bytesFrom = new byte[209666];
string dataFromClient = null;
Byte[] sendBytes = null;
requestCount = 0;
int byteread = 0;
string respdata = string.Empty;
byte[] buffer = new byte[4096];
int numberOfBytesRead;
TcpClient client = (TcpClient)obj;
NetworkStream networkStream = client.GetStream();
IPAddress address = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
Boolean bClientConnected = true;
int id = Thread.CurrentThread.ManagedThreadId;
while (bClientConnected)
{
try {
if (networkStream.DataAvailable)
{
byteread = networkStream.Read(bytesFrom, 0, (int)client.ReceiveBufferSize);
dataFromClient = Encoding.ASCII.GetString(bytesFrom).TrimEnd('\0');
System.Text.Encoding.ASCII.GetString(bytesFrom);
XmlDocument doc = new XmlDocument();
string xml = Encoding.UTF8.GetString(bytesFrom).TrimEnd('\0');
doc.LoadXml(xml);
XElement incc = XElement.Load(new XmlNodeReader(doc));
respdata = AysncTCPIncomeString(incc);
sendBytes = Encoding.ASCII.GetBytes(respdata);
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
}
}
catch (Exception ex)
{
Helper.WriteLog("Exception=" + ex.Message);
}
}
}
public void SentFirstTimeData_New(TcpClient tc)
{
try
{
int threadid = Thread.CurrentThread.ManagedThreadId;
string Msg = HLStatusResponse.FirstTimeStatusSuccessfulResponse("STATUS", "1");
NetworkStream _NetworkStream = tc.GetStream();
if (_NetworkStream != null)
{
byte[] data = Encoding.ASCII.GetBytes(Msg);
_NetworkStream.Write(data, 0, data.Length);
Helper.WriteLog("ThreadId=" + threadid.ToString() + ";SentFirstTimeData :\t " + Msg);
}
}
catch (Exception ex)
{
Helper.WriteLog("Sent Though Tcp Eror :" + ex.ToString());
}
}
}
Consider this chunk of code:
Boolean bClientConnected = true;
int id = Thread.CurrentThread.ManagedThreadId;
while (bClientConnected)
{
try {
if (networkStream.DataAvailable)
You never change bClientConnected - it is always true, so your loop never exits.
Also, if the connection is idle - that is, if networkStream.DataAvailable is false - then you just spin in your while loop doing nothing.
If you have a thread per client, why don't you just let the thread be blocked by performing a read from the socket? Then the thread won't spin wasting cpu doing nothing.
I'm having communication problems with my Program.cs class and my handleClinet.cs class.. Program handles accepting connection from every new client that attempts connecting, and handleClinet is responsible for handling every client's individual interaction.
I have a while loop in each class which is, i assume, where the problem lies.. but I'm not sure how else to do this. The server responses are not corresponding to what they're supposed to be responding. (i.e. not going into my broadcast function and executing the statements in the Program while loop) does anyone have a solution to this? Thanks in advance
class Program
{
public static Hashtable clientsList = new Hashtable();
static void Main(string[] args)
{
UdpClient server = new UdpClient(8888);
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
string data = "";
Console.WriteLine("Auction Server Started ....");
while (true)
{
try
{
//Reads data
byte[] inStream = server.Receive(ref remoteEndPoint);
data = Encoding.ASCII.GetString(inStream);
Console.WriteLine("REGISTER Client at " + remoteEndPoint);
byte[] sendBytes = Encoding.ASCII.GetBytes("REGISTERED " + remoteEndPoint.ToString());
server.Send(sendBytes, sendBytes.Length, remoteEndPoint);
handleClinet client = new handleClinet();
clientsList.Add(data, server);
client.startClient(server, data, clientsList, remoteEndPoint);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
//break;
}
}
}
//Broadcast method is used to send message to ALL clients
public static void broadcast(UdpClient dest, string msg, string uName, bool flag, IPEndPoint sendEP)
{
foreach (DictionaryEntry Item in clientsList)
{
Byte[] broadcastBytes = null;
if (flag == true)
{
broadcastBytes = Encoding.ASCII.GetBytes(msg);
}
else
{
broadcastBytes = Encoding.ASCII.GetBytes(msg);
}
dest.Send(broadcastBytes, broadcastBytes.Length, sendEP);
}
}
}//end Main class
}
public class handleClinet
{
UdpClient clientSocket;
string clNo;
Hashtable clientsList;
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
IPEndPoint myEP = new IPEndPoint(IPAddress.Any, 0);
public void startClient(UdpClient inClientSocket, string clineNo, Hashtable cList, IPEndPoint tempEP)
{
this.myEP = tempEP;
this.clientSocket = inClientSocket;
this.clNo = clineNo;
this.clientsList = cList;
Thread ctThread = new Thread(doChat);
ctThread.Start();
}
private void doChat()
{
int requestCount = 0;
byte[] bytesFrom = new byte[10025];
string dataFromClient = null;
string rCount = null;
requestCount = 0;
while ((true))
{
try
{
requestCount = requestCount + 1;
byte[] received = clientSocket.Receive(ref remoteIPEndPoint);
dataFromClient = Encoding.ASCII.GetString(received);
Console.WriteLine(dataFromClient);
rCount = Convert.ToString(requestCount);
if (dataFromClient.Contains("DEREGISTER"))
Program.broadcast(clientSocket, "DREG-CONF", clNo, true, myEP);
else
Program.broadcast(clientSocket, dataFromClient, clNo, true, myEP);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
break;
}
}//end while
}//end doChat
} //end class handleClinet
}
static void Main(string[] args)
{
Console.Title = "Socket Server";
Console.WriteLine("Listening for client messages");
Socket serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPAddress serverIp = IPAddress.Any;
IPEndPoint serverEP = new IPEndPoint(serverIp, 8000);
SocketPermission socketPermission = new SocketPermission(NetworkAccess.Accept,
TransportType.Tcp,
"127.0.0.1", 8000);
serverSocket.Bind(serverEP);
serverSocket.Listen(2);
while(true)
{
//Socket connection = serverSocket.Accept();
connection = serverSocket.Accept();
Thread clientThread = new Thread(new ParameterizedThreadStart(MultiUser));
clientThread.Start(connection);
}
}
public static void MultiUser(object connection)
{
byte[] serverBuffer = new byte[10025];
string message = string.Empty;
int bytes = ((Socket)connection).Receive(serverBuffer, serverBuffer.Length, 0);
message += Encoding.ASCII.GetString(serverBuffer, 0, bytes);
Console.WriteLine(message);
TcpClient client = new TcpClient();
client.Client = ((Socket)connection);
IntPtr handle = client.Client.Handle;
}
I want to write a chat program which has one server and 2 clients. The problem is that, I can not direct the message sent from the client1 to client2 via the server. How can the server distinguish threads so that it can send the received message from client1 to client2?
Each client has their own handle. You can access this via the Handle property. For example:
TcpClient client = tcpListener.AcceptTcpClient();
IntPtr handle = client.Client.Handle; //returns a handle to the connection
Then all you need to do is store this in a hashtable, and iterate through it, looking for available data. When you detect data on the wire for one of the connections, then save it and retransmit it to the other clients in the table.
Remember to make sure that you make this multithreaded so a listen request on one client does not block any send or receive functions on other clients!
I've added some code here you should be able to work with (tested it out on my system)
private void HandleClients(object newClient)
{
//check to see if we are adding a new client, or just iterating through existing clients
if (newClient != null)
{
TcpClient newTcpClient = (TcpClient)newClient;
//add this client to our list
clientList.Add(newTcpClient.Client.Handle, newTcpClient);
Console.WriteLine("Adding handle: " + newTcpClient.Client.Handle); //for debugging
}
//iterate through existing clients to see if there is any data on the wire
foreach (TcpClient tc in clientList.Values)
{
if (tc.Available > 0)
{
int dataSize = tc.Available;
Console.WriteLine("Received data from: " + tc.Client.Handle); //for debugging
string text = GetNetworkString(tc.GetStream());
//and transmit it to everyone else
foreach (TcpClient otherClient in clientList.Values)
{
if (tc.Client.Handle != otherClient.Client.Handle)
{
Send(otherClient.GetStream(), text);
}
}
}
}
}
public void Send(NetworkStream ns, string data)
{
try
{
byte[] bdata = GetBytes(data, Encoding.ASCII);
ns.Write(bdata, 0, bdata.Length);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
protected string GetNetworkString(NetworkStream ns)
{
if (ns.CanRead)
{
string receivedString;
byte[] b = GetNetworkData(ns);
receivedString = System.Text.Encoding.UTF8.GetString(b);
log.Info("Received string: " + receivedString);
return receivedString;
}
else
return null;
}
protected byte[] GetNetworkData(NetworkStream ns)
{
if (ns.CanRead)
{
log.Debug("Data detected on wire...");
byte[] b;
byte[] myReadBuffer = new byte[1024];
MemoryStream ms = new MemoryStream();
int numberOfBytesRead = 0;
// Incoming message may be larger than the buffer size.
do
{
numberOfBytesRead = ns.Read(myReadBuffer, 0, myReadBuffer.Length);
ms.Write(myReadBuffer, 0, numberOfBytesRead);
}
while (ns.DataAvailable);
//and get the full message
b = new byte[(int)ms.Length];
ms.Seek(0, SeekOrigin.Begin);
ms.Read(b, 0, (int)ms.Length);
ms.Close();
return b;
}
else
return null;
}
You will want to call HandleClients from a main thread that checks to see if there are any pending requests or not, and runs on a loop.
I am now using the default port number TcpListener serverSocket = new TcpListener(9999);
but because at my client side, i have put a textbox to allow user to manually key in the port number. So how do i make my server side to allow port number from port 1 to 9999 instead
using System;
using System.Threading;
using System.Net.Sockets;
using System.Text;
using System.Collections;
namespace ConsoleApplication1
{
class Program
{
public static Hashtable clientsList = new Hashtable();
static void Main(string[] args)
{
TcpListener serverSocket = new TcpListener(9999);
TcpClient clientSocket = default(TcpClient);
int counter = 0;
serverSocket.Start();
Console.WriteLine("Welcome to NYP Chat Server ");
counter = 0;
while ((true))
{
counter += 1;
clientSocket = serverSocket.AcceptTcpClient();
byte[] bytesFrom = new byte[10025];
string dataFromClient = null;
NetworkStream networkStream = clientSocket.GetStream();
networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$"));
clientsList.Add(dataFromClient, clientSocket);
broadcast(dataFromClient + " Connected ", dataFromClient, false);
Console.WriteLine(dataFromClient + " has join the chat room ");
handleClinet client = new handleClinet();
client.startClient(clientSocket, dataFromClient, clientsList);
}
clientSocket.Close();
serverSocket.Stop();
Console.WriteLine("exit");
Console.ReadLine();
}
public static void broadcast(string msg, string uName, bool flag)
{
foreach (DictionaryEntry Item in clientsList)
{
TcpClient broadcastSocket;
broadcastSocket = (TcpClient)Item.Value;
NetworkStream broadcastStream = broadcastSocket.GetStream();
Byte[] broadcastBytes = null;
if (flag == true)
{
broadcastBytes = Encoding.ASCII.GetBytes(uName + " says : " + msg);
}
else
{
broadcastBytes = Encoding.ASCII.GetBytes(msg);
}
broadcastStream.Write(broadcastBytes, 0, broadcastBytes.Length);
broadcastStream.Flush();
}
} //end broadcast function
}//end Main class
public class handleClinet
{
TcpClient clientSocket;
string clNo;
Hashtable clientsList;
public void startClient(TcpClient inClientSocket, string clineNo, Hashtable cList)
{
this.clientSocket = inClientSocket;
this.clNo = clineNo;
this.clientsList = cList;
Thread ctThread = new Thread(doChat);
ctThread.Start();
}
private void doChat()
{
int requestCount = 0;
byte[] bytesFrom = new byte[10025];
string dataFromClient = null;
Byte[] sendBytes = null;
string serverResponse = null;
string rCount = null;
requestCount = 0;
while ((true))
{
try
{
requestCount = requestCount + 1;
NetworkStream networkStream = clientSocket.GetStream();
networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf("$"));
Console.WriteLine("From client - " + clNo + " : " + dataFromClient);
rCount = Convert.ToString(requestCount);
Program.broadcast(dataFromClient, clNo, true);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}//end while
}//end doChat
} //end class handleClinet
}//end namespace
Add a setting to your program so that you can change the port...
Project properties -> Settings tab -> create a setting called PortNumber, of type Int32, with a default value of 9999
In your code, retrieve the value with Properties.Settings.Default.PortNumber
EDIT: I misread the question. Do you want to listen to all ports from 1 to 9999 at the same time ?? It doesn't make sense, because
many ports in that range will already be used by other processes
you don't need to listen on so many ports...
If you're worried about having multiple users connected at the same time, that's not an issue : just use a new thread to handle each incoming connection, and call AcceptTcpClient again on the listener on the main thread.
The best option would be to make the port number customizable via the application configuration file.
This would allow the server to change ports without a recompilation.
As far as the code goes, you just need to set the port to use here:
TcpListener serverSocket = new TcpListener(portFromAppConfig);
Also, you shouldn't use ports lower than 1024 - these are reserved ports for system services. You should stick to ports in the higher range of numbers (in general).
You don't normally have a single server listening on multiple ports; it's fairly strange. What you do is accept connections, and then pass them off for processing in another thread, and go back to accepting more connections.