C# Sockets: 2nd (and more) users can't connect - c#

I connect to my (C#) server and from an App built in Corona SDK but for the second person can never connect.
I have tried using different IP's i.e. two cellphones with external IP's with no difference.
This is how my server listener works:
server.cs
void Listener()
{
while (isRunning)
{
try
{
Socket socket = listener.AcceptSocket();
foreach (var worker in workers)
if (worker.IsAvailable)
{
worker.ProcessNewSocket(socket);
break;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
public void Run()
{
Console.WriteLine("Server.Run()");
listener.Start();
isRunning = true;
foreach (var worker in workers)
{
Thread t = new Thread(worker.Run);
t.Start();
}
Listener();
}
ServerWorker.cs
public void ProcessNewSocket(Socket socket)
{
var pc = new PlayerClient(this);
sockets.Add(socket, pc);
}
// this method will be called in cycle
public void Run()
{
while (server.IsRunning)
{
List<Socket> readList = sockets.Keys.ToList(); //List of sockets that have some data from client available for reading.
List<Socket> writeList = sockets.Keys.ToList(); //List of sockets that are ready to write (send) to the client. An action was made to a table and the change was sent to PlayerClient.Write and is now stored in the queue (MemoreStream)
List<Socket> errorList = sockets.Keys.ToList();
if (readList.Count() != 0 || writeList.Count() != 0 || errorList.Count() != 0)
{
// for providing security you can use System.Net.Security.SslStream here when read/write data,
// see http://msdn.microsoft.com/ru-ru/library/system.net.security.sslstream(v=vs.110).aspx
Socket currentSocket = null;
// foreach socket with events
try
{
foreach (var s in readList)
{
currentSocket = s;
//TODO: Get the actual length of the message.
byte[] data = new byte[2048];
s.Receive(data);
sockets[s].OnData(data);
}
foreach (var s in writeList)
{
currentSocket = s;
if (sockets[s].IsWriteDataAvailable())
{
s.Send(sockets[s].GetWriteBuffer());
sockets[s].ClearWriteBuffer();
}
}
foreach (var s in errorList)
{
//OnError
}
}
// we got exception, depending on the type...
catch (SocketException ex)
{
//Console.WriteLine(ex.ToString());
// send client error message, this is not always possible(for example network failure)
// maybe we would like to notify his opponent about connection failure
// terminate connection
if (ex.ErrorCode == (int)SocketError.ConnectionAborted || ex.ErrorCode == (int)SocketError.ConnectionReset)
RemoveSocket(currentSocket);
else
Console.WriteLine("Other problem .. " + ex.ErrorCode.ToString());
}
}
}
}
I'm new in network programming so I'm not really sure what to do. I have read about using ASync but first I would like to know if there is something I can do with this code and/or if I should change it completely?

I think the "BREAK" statement in your Listener() Block;
foreach (var worker in workers)
if (worker.IsAvailable)
{
worker.ProcessNewSocket(socket);
break; // this BREAK WILL END YOUR loop AFTER first CLIENT FOUND.
}
So, try removing break as;
foreach (var worker in workers)
{
if (worker.IsAvailable)
{
worker.ProcessNewSocket(socket);
}
}

Related

Issue with local connection between 2 programs over TCP

So I have a really really weird issue. This is going to take a tiny bit of a wall to explain fully..
I'm running some game servers for a Unity game called SCP: Secret Laboratory, and have a custom-made C# Discord Bot that helps my staff moderate both in-game and on Discord, by controlling bans, logging player warnings, etc, etc.
I'm trying to make the two platforms communicate with each other over a TCP port over the local machine address (127.0.0.1).
I've setup the listener on the bot, to whom the individual servers (there are 7) will connect to when they are ready.
I've also set it up so that if the connection is broken from either side, the servers will close the TcpClient, start a new one, and attempt to connect, while the listener just resumes listening on that port for a connection again, after closing the client on it's side.
I've tested it several times by closing the client, the socket, or just rebooting the program on either end, and they seem to without fail reconnect flawlessly.
Here's my issue..
While the game servers remain empty, everything is fine. After players start to connect, anywhere from 5mins to an hour will go by, then suddenly, seemingly at random, the server no longer 'hears' the bot when it talks across the connection, however, the bot itself does not hit an error when trying to send data, the server just never receives any. What's stranger, is the server will continue to send it's own data over the connection, and the bot does receive that data.
To attempt to 'reset' the connection with a new client when this happens, I make the servers send an initial heartbeat to the bot when they first connect. This tells the bot that the connection is established on the server's end, and begins a looping thread that will send an AYT message to the server every 10s, to which the server must reply.
If the bot sends 3 AYT messages without getting a response back, it will close the TcpClient, and start listening for a new one.
At this time, the server detects the connection was closed, disposes of it's client, instantiates a new one, and tries to connect successfully. The bot then receives it's initial heartbeat, and starts the AYT timer for that client again, but the server continues to not receive them. Or any data whatsoever sent from the bot, even though the bot still receives data from the server during this time.
The only solution to fix the problem at that point, is to fully restart the game server, after which it will connect to the bot and work perfectly fine, until it.. just doesn't anymore.
For reference, pastebins of the code used are below.
The bot "listener" side
public class ProcessSTT
{
private static ConcurrentDictionary<int, TcpClient> bag = new ConcurrentDictionary<int, TcpClient>();
private static ConcurrentDictionary<int, int> heartbeats = new ConcurrentDictionary<int, int>();
public static void SendData(string data, int port, ulong channel = 0)
{
try
{
BinaryFormatter formatter = new BinaryFormatter();
SerializedData.SerializedData serializedData =
new SerializedData.SerializedData { Data = data, Port = port, Channel = channel };
//Console.WriteLine($"Sending {serializedData.Data}");
if (!bag.ContainsKey(port))
{
Console.WriteLine($"STT: Bag does not contain {port}");
return;
}
if (bag[port] != null && bag[port].Connected)
formatter.Serialize(bag[port].GetStream(), serializedData);
else
{
Console.WriteLine($"Error - Bag {port} is null or not connected.");
if (bag.TryRemove(port, out TcpClient client))
client.Dispose();
}
}
catch (IOException s)
{
Console.WriteLine($"STT: Socket exception, removing..");
KeyValuePair<int, TcpClient> thingything = default;
foreach (var thing in bag)
if (thing.Key == port)
thingything = thing;
if (bag.TryRemove(thingything.Key, out TcpClient _client))
{
_client.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static List<TcpListener> listener = new List<TcpListener>();
public static void Init()
{
for (int i = 1; i < 8; i++)
{
TcpListener list = new TcpListener(IPAddress.Loopback, 11900 + i);
Console.WriteLine($"STT: Listener started for port {11900 + i}");
listener.Add(list);
list.Start();
ThreadPool.QueueUserWorkItem(ListenForConn, list);
}
}
public static async Task Heartbeat(int port)
{
await Task.Delay(10000);
for (;;)
{
Console.WriteLine("STT: Starting Heartbeat");
if (heartbeats[port] > 3)
{
Console.WriteLine($"STT: Removing {port} due to heartbeat timeout.");
if (bag.TryRemove(port, out TcpClient client))
client.Close();
heartbeats.TryRemove(port, out int _);
return;
}
heartbeats[port]++;
Console.WriteLine($"STT: Sending heartbeat to: {port}");
if (!bag[port].Connected)
{
Console.WriteLine($"STT: {port} is null, removing.");
if (bag.TryRemove(port, out TcpClient client))
client.Close();
return;
}
SendData("ping", port, 653737934150959115);
await Task.Delay(10000);
}
}
public static void ListenForConn(object token)
{
Console.WriteLine("STT: Listener started.");
TcpListener listen = token as TcpListener;
for (;;)
{
try
{
TcpClient thing = listen.AcceptTcpClient();
ThreadPool.QueueUserWorkItem(ListenOn, thing);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
public static async Task ReceiveData(SerializedData.SerializedData data, TcpClient client)
{
try
{
if (data == null)
{
Console.WriteLine("STT: Received data null");
return;
}
if (data.Data == "ping")
{
if (!bag.ContainsKey(data.Port))
{
Console.WriteLine($"STT: Adding {data.Port}");
bag.TryAdd(data.Port, client);
}
if (!bag[data.Port].Connected || bag[data.Port] == null)
{
Console.WriteLine($"STT: Bag {data.Port} not connected or null, removing.");
if (bag.TryRemove(data.Port, out TcpClient cli))
{
cli?.Close();
}
}
Console.WriteLine($"STT: Received heartbeat for: {data.Port}");
if (!heartbeats.ContainsKey(data.Port))
{
Heartbeat(data.Port);
heartbeats.TryAdd(data.Port, 0);
}
else
heartbeats[data.Port]--;
return;
}
Console.WriteLine(data.Data);
data.Data = data.Data.Substring(data.Data.IndexOf('#') + 1);
//Console.WriteLine("Getting guild.");
SocketGuild guild = Bot.Discord.GetGuild(478381106798788639);
//Console.WriteLine("Getting channel");
SocketTextChannel chan = guild.GetTextChannel(data.Channel);
//Console.WriteLine("Sending message.");
await chan.SendMessageAsync($"Server {data.Port -= 7770}: {data.Data}");
if (data.Port == 7771)
{
DiscordWebhookClient webhook = new DiscordWebhookClient(
"");
await webhook.SendMessageAsync($"{data.Data}");
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public static void ListenOn(object token)
{
TcpClient client = token as TcpClient;
try
{
BinaryFormatter formatter = new BinaryFormatter();
for (;;)
{
SerializedData.SerializedData serializedData;
if (!client.Connected)
{
Console.WriteLine($"Client not connected..");
client.Close();
continue;
}
serializedData = formatter.Deserialize(client.GetStream()) as SerializedData.SerializedData;
new Thread(() => ReceiveData(serializedData, client)).Start()
}
}
catch (SerializationException s)
{
Console.WriteLine($"STT: Serialization exception, removing..");
KeyValuePair<int, TcpClient> thingything = default;
foreach (var thing in bag)
if (thing.Value == client)
thingything = thing;
if (bag.TryRemove(thingything.Key, out TcpClient _client))
{
_client.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
The server "speaker" side
public class ProcessSTT
{
private static TcpClient tcpClient;
public static readonly ConcurrentQueue<SerializedData.SerializedData> dataQueue = new ConcurrentQueue<SerializedData.SerializedData>();
private static Thread _init;
private static bool _locked;
public static void Init()
{
if (_locked)
return;
_locked = true;
Thread.Sleep(1000);
try
{
Plugin.Log($"STT: Starting INIT.");
tcpClient?.Close();
tcpClient = new TcpClient();
while (!tcpClient.Connected)
{
Plugin.Log($"STT: While loop start");
Thread.Sleep(2000);
try
{
tcpClient.Connect("127.0.0.1", ServerConsole.Port + 4130);
}
catch (SocketException)
{
tcpClient.Client.Disconnect(false);
}
catch (Exception e)
{
Plugin.Log($"STT: {e}");
}
}
Thread thread = new Thread(ReceiveData);
thread.Start();
SendData("ping", 0);
_locked = false;
}
catch (IOException i)
{
_init = new Thread(Init);
_init.Start();
}
catch (Exception e)
{
ServerConsole.AddLog(e.ToString());
}
}
public static void SendData(string data, ulong channel)
{
try
{
if (!tcpClient.Connected)
throw new InvalidOperationException("Tcp Client not connected!");
SerializedData.SerializedData serializedData = new SerializedData.SerializedData
{
Data = data, Port = ServerConsole.Port, Channel = channel
};
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(tcpClient.GetStream(), serializedData);
ServerConsole.AddLog($"Sent {data}");
}
catch (IOException i)
{
_init = new Thread(Init);
_init.Start();
}
catch (Exception e)
{
ServerConsole.AddLog(e.ToString());
}
}
public static void ReceiveData()
{
try
{
if (!tcpClient.Connected)
throw new InvalidOperationException("Tcp Client not connected!");
BinaryFormatter formatter = new BinaryFormatter();
for (;;)
{
SerializedData.SerializedData deserialize =
formatter.Deserialize(tcpClient.GetStream()) as SerializedData.SerializedData;
if (deserialize == null)
continue;
dataQueue.Enqueue(deserialize);
}
}
catch (SerializationException s)
{
_init = new Thread(Init);
_init.Start();
}
catch (IOException e)
{
_init = new Thread(Init);
_init.Start();
}
catch (Exception e)
{
ServerConsole.AddLog(e.ToString());
}
}
}
public class HandleQueue
{
public static ulong channelid;
public static void HandleQueuedItems()
{
while (ProcessSTT.dataQueue.TryDequeue(out SerializedData.SerializedData result))
{
string command = result.Data;
Plugin.Log($"STT: Received {result.Data} for {result.Port}");
if (result.Port != ServerConsole.Port)
return;
if (result.Data == "ping")
{
Plugin.Log("STT: BLART Heartbeat received.");
ProcessSTT.SendData("ping", 0);
return;
}
channelid = result.Channel;
try
{
GameCore.Console.singleton.TypeCommand($"/{command}", new BlartSender());
}
catch (Exception e)
{
ServerConsole.AddLog(e.ToString());
}
}
}
public static IEnumerator<float> Handle()
{
for (;;)
{
HandleQueuedItems();
yield return Timing.WaitForSeconds(1f);
}
}
}
public class BlartSender : CommandSender
{
public override void RaReply(string text, bool success, bool logToConsole, string overrideDisplay)
{
ProcessSTT.SendData($"{text}", HandleQueue.channelid);
}
public override void Print(string text)
{
ProcessSTT.SendData($"{text}", HandleQueue.channelid);
}
public override string SenderId => "BLART";
public override string Nickname => "BLART";
public override ulong Permissions => ServerStatic.GetPermissionsHandler().FullPerm;
public override byte KickPower => Byte.MaxValue;
public override bool FullPermissions => true;
}`

NetMQ Polling a rep socket with a timeout in a loop

I'm trying to port my code from an obsolete library called CastleMQ to NetMQ but I'm running into some problems.
I prefer to using polling with a timeout, for reliability - I just found that it worked best for me from trial and error compared to just sitting blocking the port indefinitely.
here is my CastleMQ code
public int ZeroPort;
private void ThreadProc()
{
var ctx = new Context();
try {
using (var repSocket = ctx.CreateSocket(SocketType.Rep))
{
string bindAddress = "tcp://*:"+ZeroPort;
repSocket.Bind(bindAddress);
print2("*** BINDING on {0} ***", bindAddress);
bool quit = false;
while (!quit) {
try {
var polling = new Polling(PollingEvents.RecvReady, repSocket);
polling.RecvReady += (socket) =>
{ // using socket.Recv() here is guaranted to return stuff
var msg = socket.Recv();
var msgStr = Encoding.UTF8.GetString(msg);
print2("[REP:{0}] {1}", bindAddress, msgStr);
switch (msgStr) {
case "positions": {
StringBuilder csv = new StringBuilder();
print2("csv: {0}", csv.ToString());
socket.Send(csv.ToString());
break;
}
default: {
socket.Send("Unrecognized Command: " + msgStr);
break;
}
}
};
polling.Poll(POLL_TIMEOUT_MS); // this returns once some socket event happens
} catch (Exception e) {
if (e is ThreadAbortException) {
quit = true;
print2("\n*** EXITED ***");
} else print2(e.ToString());
}
}
}
} catch (Exception e) {
print2(e.ToString());
} finally {
ctx.Dispose();
}
}
here is what I tried to do and then got lost with NetMQ
private void ThreadProc()
{
try {
string bindAddress = "#tcp://*:" + ZeroPort;
print2("*** BINDING on {0} ***", bindAddress);
using (var repSocket = new ResponseSocket(bindAddress))
using (var poller = new NetMQPoller { repSocket })
{
// bool quit = false;
// while (!quit)
// these event will be raised by the Poller
repSocket.ReceiveReady += (s, a) =>
{
// receive won't block as a message is ready
string msg = a.Socket.ReceiveString(); // defeinition for ReceiveString() can't be found
// send a response
a.Socket.Send("Response"); // it doesn't like "Response", do I need to wrap it in some object?
I'm especially confused as how to add a timeout so I can poll with a timeout in a loop the way my CastleMQ code does.
Any pointers would be much appreciated, thanks

Can't connect with my bluetooth device

I have been working on this for days, but can't fix the problem.
This is what I've got right now ->
Bluetooth handler
protected BluetoothAdapter bluetoothAdapter;
protected BluetoothServer btServer;
protected BluetoothSocket btSocket;
protected BluetoothDevice pairedBTDevice;
protected BluetoothListener btListener;
protected ParcelUuid uuid;
public BluetoothHandler()
{
BluetoothAdapter = null;
}
public void Initialize()
{
BluetoothAdapter = BluetoothAdapter.DefaultAdapter;
// Check if it has a bluetooth interface
if (BluetoothAdapter == null)
{
Console.WriteLine("Bluetooth is not available!");
return;
}
// Check if bluetooth interface is enabled
if (!BluetoothAdapter.IsEnabled)
{
BluetoothAdapter.Enable();
}
int count = 0;
// Get all the devices in the bluetooth list
var listDevices = BluetoothAdapter.BondedDevices;
if (listDevices.Count > 0)
{
foreach (var btDevice in listDevices)
{
// Get the specific controller
if (btDevice.Name == "MOCUTE-032_B52-CA7E")
{
UUID = btDevice.GetUuids().ElementAt(count);
pairedBTDevice = btDevice;
}
count++;
}
}
// Check if bluetooth is enabled
// Check if there is a device
if (BluetoothAdapter.IsEnabled && pairedBTDevice != null)
{
// Check if it's paired
if (pairedBTDevice.BondState == Bond.Bonded)
{
// First start the server
btServer = new BluetoothServer(this);
Thread.Sleep(1000);
// Start a new thread
Thread thread = new Thread(new ThreadStart(Connect));
thread.Start();
}
}
}
protected void Connect()
{
// Check if there is no socket already
if (btSocket == null)
{
try
{
btSocket = pairedBTDevice.CreateRfcommSocketToServiceRecord(UUID.Uuid);
}
catch (IOException ex)
{
throw ex;
}
}
try
{
Console.WriteLine("Attempting to connect...");
// Create a socket connection
btSocket.Connect();
}
catch
{
Console.WriteLine("Connection failed...");
Console.WriteLine("Attempting to connect...");
try
{
btSocket = pairedBTDevice.CreateInsecureRfcommSocketToServiceRecord(UUID.Uuid);
btSocket.Connect();
}
catch
{
Console.WriteLine("Connection failed...");
return;
}
}
Console.WriteLine("Client socket is connected!");
Read();
}
protected void Read()
{
btListener = new BluetoothListener();
btListener.Read(btSocket);
}
Bluetooth server
private BluetoothHandler bluetoothHandler;
private BluetoothServerSocket serverSocket;
private Thread thread;
public BluetoothServer(BluetoothHandler bluetoothHandler)
{
this.bluetoothHandler = bluetoothHandler;
BluetoothServerSocket tmp = null;
try
{
tmp = bluetoothHandler.BluetoothAdapter.ListenUsingRfcommWithServiceRecord("MOCUTE-032_B52-CA7E", bluetoothHandler.UUID.Uuid);
}
catch (IOException ex)
{
throw ex;
}
serverSocket = tmp;
thread = new Thread(new ThreadStart(Run));
thread.Start();
}
protected void Run()
{
System.Console.WriteLine("Server is running...");
while (true)
{
try
{
serverSocket.Accept();
}
catch (IOException ex)
{
System.Console.WriteLine("FAILED! === > " + ex);
}
}
}
Bluetooth listener
protected Stream mmInStream;
public void Read(BluetoothSocket socket)
{
Stream tmpIn = null;
try
{
tmpIn = socket.InputStream;
}
catch (IOException ex)
{
throw ex;
}
mmInStream = tmpIn;
Thread thread = new Thread(new ThreadStart(Run));
thread.Start();
}
protected void Run()
{
byte[] buffer = new byte[1024];
int bytes;
Console.WriteLine("Waiting for events...");
while (true)
{
try
{
if (mmInStream.IsDataAvailable())
{
bytes = mmInStream.Read(buffer, 0, buffer.Length);
}
}
catch (Exception ex)
{
throw ex;
}
}
}
I would like to connect with the following controller ->
So, I would like to catch the buttons events from the controller, but I have no idea anymore..
I've got also the known error: Java.IO.IOException: "read failed, socket might closed or timeout, read ret: -1
The UUID of the controller is: 00001124-0000-1000-8000-00805f9b34fb
I have one example to connect to a Bluetooth(2.0) device on my Github you can check the code and see if you setup is correct here is the link https://github.com/AlejandroRuiz/Mono/blob/master/Arduino/Bluetooth/MainActivity.cs if you have any specific question about the code please let me know also you need to be sure what kind of bluetooth is using because the way to connect to a 4.0 BLE is very different that the old 2.0
The problem is solved. I didn't need a Bluetooth socket. I just used the override methods "KeyDown" and "KeyUp". It works great now :)
If you need a socket and you've got an exception like IOException: read failed, socket might closed then you should read my fix here:
IOException: read failed, socket might closed - Bluetooth on Android 4.3

How to determine if the tcp is connected or not?

I have tcpclient object and i want to determine if it's connected or not.
i use connected property of tcpclient but it returns the state of last operation. so its not useful.
then i use this code :
bool flag;
flag = (tcp.Client.Poll(10000, SelectMode.SelectWrite));
and
if( tcp.Client.Poll( 0, SelectMode.SelectRead ) )
{
byte[] buff = new byte[1];
if( tcp.Client.Receive( buff, SocketFlags.Peek ) == 0 )
{
flag = false;
}
}
but it does not work properly.
Any idea?
this is my code in server side :
private ArrayList _ClientList = new ArrayList();
public ClsServer(int port)
{
_TCPListener = new TcpListener(IPAddress.Any, port);
_TCPListener.Start();
Thread ListenThread = new Thread(new ThreadStart(ListenForClients));
ListenThread.IsBackground = true;
ListenThread.Start();
}
private void ListenForClients()
{
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this._TCPListener.AcceptTcpClient();
client.ReceiveTimeout = 0;
//create a thread to handle communication with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.IsBackground = true;
clientThread.Start(client);
}
}
private void HandleClientComm(object client)
{
try
{
TcpClient tcpClient = (TcpClient)client;
AddObject(tcpclient);
int bytesRead;
string message = "";
byte[] RecievedPack = new byte[1024 * 1000];
NetworkStream clientStream = tcpClient.GetStream();
while (true)
{
bytesRead = 0;
try
{
////blocks until a client sends a message
bytesRead = clientStream.Read(RecievedPack, 0, RecievedPack.Length);
int Len = BitConverter.ToInt32(RecievedPack, 0);
message = UTF8Encoding.UTF8.GetString(RecievedPack, 0, Len);
}
catch (Exception er)
{
//When Client is disconnected
if (er.GetType() == typeof(IOException))
{
RemoveObject(client);
break;
}
}
//message has successfully been received
// do something
}
RemoveObject(client);
}
catch(Exception e)
{
// RemoveObject(client);
}
}
private void AddObject(object obj)
{
int totalcount, index;
totalcount = _ClientList.Count;
index = 0;
while (index < totalcount)
{
TcpClient alcobj = (TcpClient)_ClientList[index];
try
{
if (IPAddress.Equals(((IPEndPoint)alcobj.Client.RemoteEndPoint).Address,
((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address))
{
_ClientList.Remove(alcobj);
break;
}
index++;
}
catch (Exception er)
{
if (er.GetType() == typeof(ObjectDisposedException))
RemoveObject(alcobj);
}
finally
{
totalcount = _ClientList.Count;
}
}
_ClientList.Add(obj);
}
private void RemoveObject(object obj)
{
if (_ClientList.IndexOf(obj) > -1)
{
_ClientList.Remove(obj);
SendClientState(IP, false);
}
}
and this is the client side :
public bool IsConnected
{
try
{
if (_TcpClient != null && _TcpClient.Client != null && _TcpClient.Client.Connected)
{
// Detect if client disconnected
if (_TcpClient.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (_TcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
{
// Client disconnected
return false;
}
else
{
return true;
}
}
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
private void clsClient()
{
if(!IsConnected())
{
Connecttoserver()
}
}
private void ConnectToServer()
{
try
{
NetworkStream _NetworkStream = _TcpClient.GetStream();
byte[] _RecievedPack = new byte[1024 * 1000];
string _Message = string.Empty;
int _BytesRead;
int _Length;
while (true)
{
_BytesRead = _NetworkStream.Read(_RecievedPack, 0, _RecievedPack.Length);
_Length = BitConverter.ToInt32(_RecievedPack, 0);
_Message = UTF8Encoding.UTF8.GetString(_RecievedPack, 4, _Length);
if (_BytesRead != 0)
{
if (OnReceive != null)
// do something
_NetworkStream.Flush();
}
}
}
catch (Exception exp)
{
// do something
}
}
in client side, IsConnected() always return false and try to connecttoserver, so the server listener always try to add the client in a list
Use this code instead, I have tested it and using it in real production software:
public bool IsConnected
{
get
{
try
{
if (_tcpClient != null && _tcpClient.Client != null && _tcpClient.Client.Connected)
{
/* pear to the documentation on Poll:
* When passing SelectMode.SelectRead as a parameter to the Poll method it will return
* -either- true if Socket.Listen(Int32) has been called and a connection is pending;
* -or- true if data is available for reading;
* -or- true if the connection has been closed, reset, or terminated;
* otherwise, returns false
*/
// Detect if client disconnected
if (_tcpClient.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (_tcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
{
// Client disconnected
return false;
}
else
{
return true;
}
}
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
}
Edit: However you can't rely on just checking the connection and if true proceed, because it returning the status of connection at time this property executed, for instance after you check IsConnected and it returns true, and while you are in the middle of communication, the connection maybe lost there! we just use it in the first place to reduce the probability of failure, So you have to wrap the whole communication in a try/catch and expect the connection to be lost at any time!
I suggest not relaying on such methods.
For my opinion, the best way is to implement some kind of keep-alive mechanism.
Every X seconds, send a small message and wait for an answer.
You're probably disconnected when:
1. You catch an exception when trying to send a keep-alive message (if you're the client side).
2. You don't get a keep-alive message/response for some period of time.
I also suggest not to count on the built-in TCP keep-alive, I found it very not-reliable.
Updated: Found a nice post for this matter: Post
The only way to know whether or not the other end of a socket connection is still connected is by catching the result of a read or write operation or possibly catching an exception.
For more information please refer to this StackOverflow question:
Instantly detect client disconnection from server socket
Here is a small snippet of code that is simply using a Socket in non-blocking mode and connected to a server.
try
{
bytesRead = nambSok.Receive(message, 4096, SocketFlags.None);
}
catch (SocketException e)
{
//a socket error has occured
switch (e.SocketErrorCode)
{
case System.Net.Sockets.SocketError.TimedOut:
case System.Net.Sockets.SocketError.WouldBlock:
if (doDisconnect == false)
{
continue;
}
break;
case System.Net.Sockets.SocketError.ConnectionReset:
case System.Net.Sockets.SocketError.ConnectionAborted:
isConnected = false;
break;
}
}
if (bytesRead > 0)
{
/* do something with data */
}
The "keep-alive" method Lior Ohana proposed is also a great idea. Force each client to "check in" every X seconds. The client can detect the server is gone if an exception occurs on the write, and the server knows the client has gone away if a "keep-alive" message hasn't been received in X seconds.
I agree with Lior Ohana because I had this problem with remote devices that were used GPRS Tcp connection. when device is turn off or disconnected, it did not alert to the sever. There for I used this code: I send Specific time to the clients
void AnalyzeForHandShaking(Socket socketin, string Message)
{
Socket handler = socketin;
try
{
Message = Message.Trim();
if (!string.IsNullOrEmpty(Message.Trim()))
// if (Message.Equals("~"))
{
// string Serial = getSerialFromSocket(socketin).Trim();
DateTime dt = DateTime.Now;
if (handler!=null)
//if there is serial in hastable
if (!arrIPTimeHandShaking.ContainsKey(handler))
{
arrIPTimeHandShaking.Add(handler, dt);
}
else
{
arrIPTimeHandShaking[handler] = dt;
}
}
}
catch
{
}
}

Constantly running server

When a client disconnects, the server closes. Tell me how to leave the ability to connect new customers after the close of the first session .Thanks in advance.
namespace tcpserver
{
class Program
{
static void Main(string[] args)
{
string cmd;
int port = 56568;
Server Serv = new Server(); // Создаем новый экземпляр класса
// сервера
Serv.Create(port);
while (true)
{
cmd = Console.ReadLine(); // Ждем фразы EXIT когда
// понадобится выйти из приложения.
// типа интерактивность.
if (cmd == "EXIT")
{
Serv.Close(); // раз выход – значит выход. Серв-нах.
return;
}
}
//while (Serv.Close() == true) { Serv.Create(port); }
}
public class Server // класс сервера.
{
private int LocalPort;
private Thread ServThread; // экземпляр потока
TcpListener Listener; // листенер))))
public void Create(int port)
{
LocalPort = port;
ServThread = new Thread(new ThreadStart(ServStart));
ServThread.Start(); // запустили поток. Стартовая функция –
// ServStart, как видно выше
}
public void Close() // Закрыть серв?
{
Listener.Stop();
ServThread.Abort();
return;
}
private void ServStart()
{
Socket ClientSock; // сокет для обмена данными.
string data;
byte[] cldata = new byte[1024]; // буфер данных
Listener = new TcpListener(LocalPort);
Listener.Start(); // начали слушать
Console.WriteLine("Waiting connections on " + Convert.ToString(LocalPort) + " port");
try
{
ClientSock = Listener.AcceptSocket(); // пробуем принять клиента
}
catch
{
ServThread.Abort(); // нет – жаль(
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();
Console.WriteLine("<" + data);
if (data == "CLOSE") // если CLOSE –
// вырубимся
{
ClientSock.Send(Encoding.ASCII.GetBytes("Closing the server..."));
ClientSock.Close();
Listener.Stop();
Console.WriteLine("Server closed. Reason: client wish! Type EXIT to quit the application.");
ServThread.Abort();
return;
}
else
{ // нет – шлем данные взад.
ClientSock.Send(Encoding.ASCII.GetBytes("Your data: " + data));
}
}
}
catch
{
ClientSock.Close(); //
Listener.Stop();
Console.WriteLine("Client disconnected. Server closed.");
ServThread.Abort();
}
}
}
}
}
}
}
Typical threaded server code will read more like this (in a pseudo code, because I don't know enough Java details to write it exactly, and because C is a bit stifling):
socket s = new socket
bind s to an optional IP, port
listen s
while true
cli = accept s
t = new thread(handle_client, cli)
maybe disown thread, so no need to join it later
t.start
The important point is that creating the socket, binding it to an address, and listen are all handled outside the loop, and accept() and starting threads are inside the loop.
You may want to wrap this entire block inside another thread; that is acceptable. The important part is separating the listen from the accept and per-client thread. This allows your code to stop accepting new connections but handle existing clients until they disconnect, or disconnect existing connections when they use their allotment of resources but continue accepting connections, etc. (Note how your last catch block will terminate the server if any single client socket throws an exception; that kind of code is easy to avoid with the usual server layout.)
replace
ServThread.Abort();
return;
with a continue instead, this will not break the while loop and yet stop the current "round". Please consider reading this: http://www.codeproject.com/KB/IP/serversocket.aspx nice project to build from

Categories

Resources