TCP Server async in WebService - c#

Im implementing a WebService with TCP. The webservice is the Server side that accept multiple clients. Is there any suggestions on how to configure a default port where to start the tcp clients? And with every client connected (aprox. 10 clients) will have an assigned port.
(I'm using Visual Studio 2010 the language is c#, Here is a code block for accepting the clients.)
Any suggestions will be accepted. Thanks!
private void StartListening(object sender, EventArgs e)
{
try
{
//Will move one the array of threads
index++;
//Will get the current IP Address
IPAddress ipaddr = IPAddress.Any;
//Port where the data will pass.
//First Port in use. 10,000
int Port = 10000;
if (true)
{
_TCPListener = new TcpListener(ipaddr, Port);
Port = Port + 1;
//Start Listening
_TCPListener.Start();
ThreadStart.Add(new ThreadStart(() => _TCPListener.BeginAcceptTcpClient(CompleteAcceptClient, _TCPListener)));
Thread.Add(new Thread(ThreadStart[index]));
Thread[index].Start();
}
else
{
_TCPListener = new TcpListener(ipaddr, Port + 2);
_TCPListener.Start();
ThreadStart delegateT = new ThreadStart(() => _TCPListener.BeginAcceptTcpClient(CompleteAcceptClient, _TCPListener));
Thread T = new Thread(delegateT);
T.Start();
}
}
catch(Exception ex)
{
throw ex;
}
}
//Here is the accept client method.
private void CompleteAcceptClient(IAsyncResult iar)
{
TcpListener tcpl = (TcpListener)iar.AsyncState;
try
{
ThreadStart delegateR = new ThreadStart(() => _TCPClient = tcpl.EndAcceptTcpClient(iar));
Thread R = new Thread(delegateR);
R.Start();
mRx = new byte[1024];
_TCPClient.GetStream().BeginRead(mRx, 0, mRx.Length, onCompleteReadFromTCPClientStream, _TCPClient);
}
catch(Exception e)
{
throw e;
}
}

Related

C# TCP listener not catching exception

I have the following configuration for the server, that connects successfully to the client and runs the following threads.
My issue is when the client disconnects, it doesn't catch the exception:
private void Form1_Load(object sender, EventArgs e)
{
th_StartListen = new Thread(new ThreadStart(StartListen));
th_StartListen.Start();
txtCmdOutput.Focus();
}
private void StartListen()
{
//Creating a TCP Connection and listening to the port
tcpListener = new TcpListener(System.Net.IPAddress.Any, 6666);
tcpListener.Start();
toolStripStatusLabel1.Text = "Listening on port 6666 ...";
int counter = 0;
appStatus = 0;
while (true)
{
try
{
client = tcpListener.AcceptTcpClient();
counter++;
clientList.Add(client);
var ipend = (IPEndPoint)client.Client.RemoteEndPoint;
//Updating status of connection
toolStripStatusLabel1.Text = "Connected from " + ipend.Address.ToString();
appStatus = 1;
th_inPutStream = new Thread(() => outPutStream(client));
th_inPutStream.Start();
th_inPutStream = new Thread(() => inPutStream(client));
th_inPutStream.Start();
}
catch (Exception err)
{
Cleanup();
}
}
}
It simply loops back and stops at client = tcpListener.AcceptTcpClient(); .
Would appreciate some ideas behind this.
Thanks!
Look carefully at your logic. Since both input stream and output stream are running on separate threads, the code will continue executing after starting the second thread, and when it does so, it will loop around, hit the true condition, and then start listening for a new client connection immediately.
Your exception isn't being caught because you're not generating an exception. A client closing it's connection to the server isn't necessarily an exception generating event.

TCP server and client at once

I am trying to create a blockchain example where all clients work as a server and a client at once. I have a thread which constantly listens for incoming connections and when a client is accepted, it creates a thread which reads the incoming data and sends data aswell. It works one way, for example if just one server is started and I join to it as a client, but for example I want to start 3 instances and start a server on all 3 of them, and then I want to connect to instance 2 from instance 1 and so on... This is the code for acceping clients and the join, host function:
TcpClient Join()
{
int server_port = int.Parse(port.Text);
klient = new TcpClient();
try
{
klient.Connect("localhost", server_port);
if (klient.Connected) //Če se poveže
{
Console.WriteLine("Connected to server.");
myNetworkStream = klient.GetStream();
}
}
catch (Exception e)
{
}
return klient;
}
TcpListener Host()
{
int port = FreeTcpPort();
IPAddress ip_address = IPAddress.Parse("127.0.0.1"); //parsing ipja
TcpListener host = new TcpListener(ip_address, port);//ustvari listener
label1.Text = port.ToString();
try
{
host.Start();//zagon strežnika
Console.WriteLine("Server started...");
mine_button.Enabled = true;
Sprejemaj_cliente = new Thread(Cakaj_na_clienta);
Sprejemaj_cliente.Start(host);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
return host;
}
public void Cakaj_na_clienta(object argument)
{
TcpListener host = (TcpListener)argument;
try
{
while (true) //ČAKANJE NA POŠILJATELJA
{
Console.WriteLine("Waiting for client...");
TcpClient client = host.AcceptTcpClient();
klient = client;
MessageBox.Show("Client connected");
string odjemalec_IP = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
int odjemalec_PORT = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
Console.WriteLine("Povezal se je pošiljatelj na naslovu " + odjemalec_IP + ":" + odjemalec_PORT); //Zagon strežnika
myNetworkStream = klient.GetStream();
sync_thread = new Thread(Synchronize);
sync_thread.Start();
send_chain = new Thread(Send_Chain);
send_chain.Start();
}
}
catch (SocketException e)
{
}
}

system.net.sockets.socketexception the remote server closed connection

I have this code on my server side.
public static void Data_IN(object cSocket)
{
Socket clientSocket = (Socket)cSocket;
byte[] Buffer;
int readBytes;
while (true)
{
Buffer = new byte[clientSocket.SendBufferSize];
readBytes = clientSocket.Receive(Buffer);
if (readBytes > 0)
{
Packet p = new Packet(Buffer);
DataManager(p);
}
}
}
And the main problem is that when I stop debugging the code the server always crashes and says
System.Net.Sockets.SocketException: the remote server closed connection
The error is always at readBytes = clientSocket.Recieve(Buffer);
That is the only way I can crash the server, my only concern is when someone uses the chat program that I have created and his/hers computer crashes the chat server will go down and I always need to restart the server.
Clientside code below which executes when closing the window
private void MainWindow_Closed(object sender, EventArgs e)
{
if (isConnected)
{
Packet p = new Packet(PacketType.CloseConnection, ID);
p.data.Add(login);
p.data.Add("exits from chat");
socket.Send(p.ToBytes());
socket.Close();
isConnected = false;
thread.Abort();
}
}
On below there is the code part which uses data_in, that code is on the client side
private void ConnectBtn_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(Login.Text))
{
MessageBox.Show("Add username");
}
else if (!IPAddress.TryParse(serverIP.Text, out ipAdress))
{
MessageBox.Show("Add valid ip");
}
else
{
ClearRequireMsg();
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(ipAdress, 4242);
try
{
socket.Connect(ipEndPoint);
login = Login.Text;
isConnected = true;
ConnectBtn.IsEnabled = false;
SendBtn.IsEnabled = true;
thread = new Thread(Data_IN);
thread.Start();
}
catch (SocketException ex)
{
AddMsgToBoard("Error during connecting to server", "System");
}
}
}
You're calling the function Data_IN without passing any parameter.
thread = new Thread(Data_IN);
Right way:
new Thread(() => Data_IN(socket));

How can I accept two or more clients in the same server c# tcp/ip

I'm trying to make my code accept two or more clients to my server program. Here is the code. I need help with the code on how to accept multiple clients at the same time. I got an error with the port. It says "Only one usage of each socket address (protocol/network address/port) is normally permitted"
namespace TCPServer
{
public partial class Form1 : Form
{
//Create TCP/IP Socket
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
TcpListener mTCPListener;
TcpClient mTCPClient = new TcpClient();
NetworkStream serverStream;
byte[] mRx;
public Form1()
{
InitializeComponent();
}
void onCompleteAcceptTcpClient(IAsyncResult iar)
{
TcpListener tcpl = (TcpListener)iar.AsyncState;
try
{
ThreadStart delegateR = new ThreadStart(() =>
mTCPClient = tcpl.EndAcceptTcpClient(iar));
Thread R = new Thread(delegateR);
R.Start();
printLine("Client Connected...");
//Begin Asynchronous Read
mRx = new byte[1024];
mTCPClient.GetStream().BeginRead(mRx, 0, mRx.Length, onCompleteReadFromTCPClientStream, mTCPClient);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnStartListening_Click_1(object sender, EventArgs e)
{
try
{
IPAddress ipaddr;
int nPort = 23000;
#region Validating IP Address
//if (!int.TryParse(tbPort.Text, out nPort))
//{
// nPort = 23000;
//}
if (!IPAddress.TryParse(tbIPAddress.Text, out ipaddr))
{
MessageBox.Show("Invalid IP address supplied.");
return;
}
#endregion
mTCPListener = new TcpListener(ipaddr, nPort);
//Start Listening
mTCPListener.Start();
//ThreadStart delegateT = new ThreadStart(() => { RefreshLot(lotId); });
//Thread T = new Thread(delegateT);
//T.Start();
ThreadStart delegateT = new ThreadStart(() => mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
Thread T = new Thread(delegateT);
T.Start();
//Begin accept tcp client (only one)
//mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
if (mTCPListener.Pending())
{
nPort = nPort + 1;
mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener);
}
}
catch (Exception ex)
{
throw ex;
}
}
void onCompleteReadFromTCPClientStream(IAsyncResult iar)
{
TcpClient tcpc;
int nCountReadBytes = 0;
string strRecv;
try
{
tcpc = (TcpClient)iar.AsyncState;
nCountReadBytes = tcpc.GetStream().EndRead(iar);
if (nCountReadBytes == 0)
{
MessageBox.Show("Client disconnected.");
return;
}
strRecv = Encoding.ASCII.GetString(mRx, 0, nCountReadBytes);
printLine(strRecv);
mRx = new byte[1024];
tcpc.GetStream().BeginRead(mRx, 0, mRx.Length, onCompleteReadFromTCPClientStream, tcpc);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public void printLine(string _strPrint)
{
tbConsoleOutput.Invoke(new Action<string>(doInvoke), _strPrint);
}
public void doInvoke(string _strPrint)
{
tbConsoleOutput.Text = _strPrint + Environment.NewLine + tbConsoleOutput.Text;
}
private void onCompleteWriteToClientStream(IAsyncResult iar)
{
try
{
TcpClient tcpc = (TcpClient)iar.AsyncState;
tcpc.GetStream().EndWrite(iar);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnSend_Click_1(object sender, EventArgs e)
{
byte[] tx = new byte[1024];
if (string.IsNullOrEmpty(tbPayload.Text)) return;
try
{
if (mTCPClient != null)
{
if (mTCPClient.Client.Connected)
{
//This is the message that will be sent
tx = Encoding.ASCII.GetBytes("Server MESRII sent: " + tbPayload.Text + " " + DateTime.Now);
mTCPClient.GetStream().BeginWrite(tx, 0, tx.Length, onCompleteWriteToClientStream, mTCPClient);
}
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnStartListening2_Click(object sender, EventArgs e)
{
}
}
You should create single TcpListener on your server, besause only one listener can use one port.
When you getting new connection (AcceptTcpClient method), you may begin new thread for messaging exchange with client.
You can see good examples in this question
I was working in the code and took all the suggestions provided. What I did was Call the Start listening this way...
`private void btnStartListening_Click_1(object sender, EventArgs e)
{
try
{
index++;
IPAddress ipaddr = IPAddress.Any;
int x = Convert.ToInt32(tbPort.Text);
int nPort = x;
//#region Validating IP Address
//if (!int.TryParse(tbPort.Text, out nPort))
//{
// nPort = 23000;
//}
//if (!IPAddress.TryParse(tbIPAddress.Text, out ipaddr))
//{
// MessageBox.Show("Invalid IP address supplied.");
// return;
//}
//#endregion
if (nPort >= 23000)
{
nPort = nPort + 1;
mTCPListener = new TcpListener(ipaddr, nPort);
//Start Listening on port nPort + 1
mTCPListener.Start();
testingThreadStart.Add(new ThreadStart(() => mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener)));
//ThreadStart delegateT = new ThreadStart(() => mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
testingThread.Add(new Thread(testingThreadStart[index]));
//Thread T = new Thread(delegateT);
//T.Start();
testingThread[index].Start();
//Begin accept tcp client (only one)
//mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
}
else
{
mTCPListener = new TcpListener(ipaddr, nPort + 1);
//Start Listening on port 23000
mTCPListener.Start();
ThreadStart delegateT = new ThreadStart(() => mTCPListener.BeginAcceptTcpClient(onCompleteAcceptTcpClient, mTCPListener));
Thread T = new Thread(delegateT);
T.Start();
}
}`
Also added list of threads on the beginning of the code...
List<ThreadStart> testingThreadStart = new List<ThreadStart>();
List<Thread> testingThread = new List<Thread>();
and thats how it worked. If anyone need/want the complete code, I can post it. For future examples.

How do I get all servers' IP which are listening on specific port LAN?

How do I get all servers IP which are listening on specific port (Ex:9090) in LAN
I have already read some basics information about multicast,anycast ,unicast and broadcast and it seems like broadcast is the one meant for my application.
I am thinking of two ideas .. Use TCP protocol to Connect to all IP Addresses (192.168.1.1-254) in parallel on port 9090 and set a little time period to the connection timeout. just to check if there's any responce. (but it doesn't seem like a good idea)Use UDP protocol and broadcast a message like "hello" and check for response then get all IP Addresses which respond.
So which idea should I pick, are there better ideas to do it?
I would also like to know if my broadcast-ed message is received to the server and how to get the IP address of it.
I've done it with TCP to search all server that is listening on a specific port.
Its not an idle solution, but it worked for me.
I've created a userControl with a public function Initialize to pass the port that i want to scan for servers.
public ServerDiscovery()
{
InitializeComponent();
// statusLabel.Image = imageState.Images[2];
timer.Elapsed += timer_tick;
}
int port = 0;
bool busy = false; // to tell that the function is busy with scanning.
public void Initialize(int port)
{
this.port = port;
}
System.Timers.Timer timer = new System.Timers.Timer(5000);
List<SocketAsyncEventArgs> list = new List<SocketAsyncEventArgs>();
// this list to hold all sockets that created to connect to IP .. to DISPOSE it later
HashSet<string> usedIP = new HashSet<string>();
//usedIP will be explained later.
public IPEndPoint getAddress()
{ //this function to get the IPEndPoint of the selected server from listview.
if (listServer.SelectedItems.Count > 0)
{
if (listServer.SelectedItems[0].ImageIndex == 0)
{
ListViewItem item = listServer.SelectedItems[0];
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(item.SubItems[1].Text), port);
return ep;
}
}
return null;
}
public void Refresh() //to scan for servers
{
if (!busy)
{
usedIP.Clear();
listServer.Items.Clear();
// statusLabel.Text = "Scanning for servers.";
// statusLabel.Image = Image.FromFile("loading.gif");
// btnRefresh.Enabled = false;
busy = true;
timer.Start();
IPAddress[] IpA = Dns.GetHostByName(Dns.GetHostName()).AddressList;
for (int j = 0; j < IpA.Length ; j++)
{
if (IpA[j].AddressFamily == AddressFamily.InterNetwork) // to make sure it's an IPV4
{
string scanIP = IpA[j].ToString().Substring(0, IpA[j].ToString().LastIndexOf(".")) + ".";
if (!usedIP.Contains(scanIP))
//usedIP is a hashset that holds the first 3 parts on an ip (ex:"192.168.1." from "192.168.1.30") i used this to avoid scanning the same ip addresses more than once .. like if i had a wireless network ip ("192.168.1.5") and an Ethernet Network ip ("192.168.1.5"). so with that hashset it will scan once.
{
usedIP.Add(scanIP);
Parallel.For(1, 255, i =>
{
Scan(scanIP + i);
});
}
}
}
}
}
private void Scan(string ipAdd)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ipAdd), port);
e.UserToken = s;
e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
list.Add(e); // add the created socket to a list to dispose when time is up.
s.ConnectAsync(e);
}
private void e_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.ConnectSocket != null) //if there's a responce from the server [e.ConnectSocket] will not be equal null.
{
StreamReader sr = new StreamReader(new NetworkStream(e.ConnectSocket));
ListViewItem item = new ListViewItem();
string[] cmd = sr.ReadLine().Split('<'); in my server constructor this line will receive a string like "PC_NAME<Available" ..
item.Text = cmd[0];
item.SubItems.Add(((IPEndPoint)e.RemoteEndPoint).Address.ToString());
item.SubItems.Add(cmd[1]);
if (cmd[1] == "Busy")
item.ImageIndex = 1;
else
item.ImageIndex = 0;
AddServer(item);
list.Remove(e); //active server should be remove from the list that holds the sockets and disposed.. because there's no need to keep connection after showing that this server is active.
((Socket)e.UserToken).Dispose();
}
}
delegate void AddItem(ListViewItem item);
private void AddServer(ListViewItem item)
{
if (InvokeRequired)
{
Invoke(new AddItem(AddServer), item); //just to add an item from a background thread.
return;
}
listServer.Items.Add(item);
}
private void timer_tick(object sender, EventArgs e)
{
busy = false; //when time's up .. set busy to false so we can scan again
timer.Stop();
foreach (var s in list) //dispose all sockets that's trying to connect and waiting for a response
{
try
{
((Socket)s.UserToken).Dispose();
}
catch { }
}
//this.Invoke((MethodInvoker)delegate // for design
// {
// btnRefresh.Enabled = true;
// btnRefresh.BorderStyle = Border3DStyle.Raised;
// statusLabel.Text = "Ready.";
// statusLabel.Image = imageState.Images[2];
// });
}
private void btnRefresh_Click(object sender, EventArgs e)
{
// btnRefresh.BorderStyle = Border3DStyle.Sunken;
Refresh();
}
// private void listServer_KeyUp(object sender, KeyEventArgs e)
// {
// if (e.KeyCode == Keys.F5)
// {
// btnRefresh_Click(sender, (EventArgs)e);
// }
// }
}
Again this's not an ideal solution that works on any case but it worked fine with me.

Categories