Closing an open socket in Unity - c#

This is a follow on from this question
After some more Googling last night I managed to find a nice TCP tutorial I could follow that would allow me to look for connections on an Ip address and port number and display the data that is being sent.
However, I have an issue where my client connects once, I send a message and display it in the debug log but when I stop the application and run it again, Unity freezes. I'm at a loss as to why this happening. Could someone please take a look over this code to see where it might be happening and what I can do to fix it?
I also seem to boot out the connection as soon as I receive a message as well, why is that? The server can re-connect, but I want it to keep the connection once it has it.
public class TCP : MonoBehaviour
{
string ip_address = "127.0.0.1";
int port = 22;
Thread listen_thread;
TcpListener tcp_listener;
Thread clientThread;
TcpClient tcp_client;
bool isTrue = true;
// Use this for initialization
void Start ()
{
IPAddress ip_addy = IPAddress.Parse(ip_address);
tcp_listener = new TcpListener(ip_addy, port);
listen_thread = new Thread(new ThreadStart(ListenForClients));
listen_thread.Start();
Debug.Log("start thread");
}
private void ListenForClients()
{
this.tcp_listener.Start();
while(isTrue == true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcp_listener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
Debug.Log("Got client " + client);
}
}
private void HandleClientComm(object client)
{
tcp_client = (TcpClient)client;
NetworkStream client_stream = tcp_client.GetStream();
byte[] message = new byte[4096];
int bytes_read;
while(isTrue == true)
{
bytes_read = 0;
try
{
//blocks until a client sends a message
bytes_read = client_stream.Read(message, 0, 4096);
//Debug.Log(message);
}
catch (Exception e)
{
//a socket error has occured
Debug.Log(e.Message);
break;
}
if(bytes_read == 0)
{
//client has disconnected
Debug.Log("Disconnected");
tcp_client.Close();
break;
}
ASCIIEncoding encoder = new ASCIIEncoding();
Debug.Log(encoder.GetString(message,0,bytes_read));
}
if(isTrue == false)
{
tcp_client.Close();
Debug.Log("closing tcp client");
}
}
void OnApplicationQuit()
{
try
{
tcp_client.Close();
isTrue = false;
}
catch(Exception e)
{
Debug.Log(e.Message);
}
}
}
Here is a screen shot of my debug log as well to show whats happening:
update
updated code that has fixed the kicking of clients. The freeze issue is still persistent when I stop the unity application and re-start it.
further update
So after a little further experimenting I have worked out that my project isn't actually freezing. When I start the server (Unity) app the first time everything works fine. But when I close it and try to re run the server, it freezes, until I connect to it with a client. At which point the server works as normal.
So I think I'm not closing the open socket when I close down the server. How can I do that?

You must close the TCP socket that is listening. If you start the application for the first time, the TCP socket will be open. When you stop the application, the TCP socket is still opened and runs in the background.
void OnApplicationQuit()
{
try
{
tcp_client.Close();
isTrue = false;
}
catch(Exception e)
{
Debug.Log(e.Message);
}
// You must close the tcp listener
try
{
tcp_listener.Stop();
isTrue = false;
}
catch(Exception e)
{
Debug.Log(e.Message);
}
}

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.

C# TCPListener keep listening after application shutdown only for the first time

I have an issue with my application,
I have a TCPListener which listen let's say on port 14000
After the application is being closed I can see on the CMD that the listener is still listening.
At the second run of the application as expected I cant start the listener on the same port (14000) because it is already taken, I am changing the application port to 15000 on the second running, work wonderful and the listener is being CLOSED after the application is being shut down,
I assume that on the first run, the first listener on port 14000 stays open after the app is dead, on the second run the application closed/open the listener on port 15000 very well, why is this happen? I thought maybe it is about the port 14000 I've switched the orders of the opening ports (first opened 15000) and saw that the 15000 stays open and the 14000 (on the second run) closed and open correctly, Why at the first run the listener not being closed??
The code to my server:
class Server : IDisposable
{
private const int TIMER_PERIOD = 60 * 1000; // ms
private string servePort;
private string serverIP;
byte[] DataReceived = new byte[1024];
Action<string> MssageReceiveCallback;
private bool isListening = false;
static Timer serverTimer = null;
private TcpListener _Server;
private Dictionary<int, TcpClient> clientsList = new Dictionary<int, TcpClient>();
private bool serverListening = true;
private static int ClientInstance = 0;
public Server(string _serverIP, string _serverPORT, Action<string> messageReceiveCallback)
{
serverIP = _serverIP;
servePort = _serverPORT;
MssageReceiveCallback = messageReceiveCallback;
// InitilizeServer();
}
private void InitilizeServer()
{
_Server = new TcpListener(IPAddress.Parse(serverIP), int.Parse(servePort));
// if (serverTimer == null)
// serverTimer = new Timer(new TimerCallback(OnTimerCallback), null, TIMER_PERIOD, TIMER_PERIOD);
Task.Run(() =>
{
try
{
_Server.Start();
while (_Server != null)
{
TcpClient tcpClient;
try
{
tcpClient = _Server.AcceptTcpClient();
}
catch
{
continue;
}
Task.Run(() =>
{
ClientInstance++;
int currentinstance = ClientInstance;
clientsList.Add(currentinstance, tcpClient);
try
{
while (tcpClient.Connected && serverListening)
{
if (tcpClient.GetStream().DataAvailable)
{
int actualBufferlength = tcpClient.GetStream().Read(DataReceived, 0, DataReceived.Length);
byte[] data = new byte[actualBufferlength];
Buffer.BlockCopy(DataReceived, 0, data, 0, actualBufferlength);
string asciiMessage = Encoding.ASCII.GetString(data);
MssageReceiveCallback(asciiMessage);
}
else
{
Thread.Sleep(5);
}
}
}
catch (Exception ex)
{
}
finally
{
clientsList[currentinstance].Close();
clientsList.Remove(currentinstance);
}
});
}
}
catch (Exception ex)
{
}
});
}
public void StartServer()
{
InitilizeServer();
isListening = true;
}
public void SendMessage(string msg)
{
byte[] data = ASCIIEncoding.ASCII.GetBytes(msg);
foreach (TcpClient client in clientsList.Values)
{
client.GetStream().Write(data, 0, data.Length);
}
}
public void Dispose()
{
serverListening = false;
foreach (var item in clientsList.Values)
{
if (item.Connected)
item.Close();
}
_Server.Server.Close();
}
}
UPDATE:
I've check in TCPView to see which application the listener bind to and found this:
It looks like the listener available for un exist process
The biggest problem here, I think (I've pointed out other problems in the comments) is that TCP shutdown requires network communications and by default prevents socket reuse for a period of time.
The function you need to get to is Socket.SetSocketOption, specifically the ReuseAddress option. You should be able to get at it via the Server property on the TcpListener. Pay attention that it needs to be done before you actually start the listener listening.
You could try putting:
_Server.Server =null;
After close.

C# UDP packetloss though all packets arrive (WireShark)

As the title says I have a problem with UDP in C#.
I'm trying to build a library for the rcon protocol of the game DayZ.
My problem is that I dont receive every packet I should receive.
After sending a command the server replies with an split answer. The packet header contains the total packet count and the index of the current packet.
Now if I should get 17 packets I only get 8-15 packets in my application.
After testing with WireShark I know now that all packages arrive on my computer. They just dont get recognized by my application or something like that.
My Actual Question is:
Is it possible to prevent losing the packages between my network card and my application? or
Why does that happen?
Here is my current code. Its pretty dirty because I ripped it apart after not working as expected:
private Socket _udpClient;
private Thread _receiverThread;
private Thread _workerThread;
private Queue<byte[]> _packetQueue;
private PacketBuffer[] MessageBuffer;
private byte SenderSequence = 0;
private IPEndPoint connection;
public RCon(IPAddress ip, int port)
{
connection = new IPEndPoint(ip, port);
_udpClient = new Socket(connection.Address.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
_udpClient.Connect(connection);
MessageBuffer = new PacketBuffer[256];
_packetQueue = new Queue<byte[]>();
_receiverThread = new Thread(new ThreadStart(ReceiveCallback));
_receiverThread.IsBackground = true;
_receiverThread.Priority = ThreadPriority.AboveNormal;
_receiverThread.Start();
_workerThread = new Thread(new ThreadStart(WorkerCallback));
_workerThread.IsBackground = true;
_workerThread.Start();
}
public void Login(string password)
{
LoginPacket packet = new LoginPacket(password);
_udpClient.Send(packet.Bytes);
}
public void SendCommand(string command)
{
CommandPacket packet = new CommandPacket(SenderSequence, command);
SenderSequence++;
_udpClient.Send(packet.Bytes);
}
private void ReceiveCallback()
{
while (true)
{
byte[] buffer = new byte[1036];
if (_udpClient.Receive(buffer) > 0)
_packetQueue.Enqueue(buffer);
}
}
private void WorkerCallback()
{
while (true)
{
if (_packetQueue.Count > 0)
{
byte[] buffer = _packetQueue.Dequeue();
if (buffer != null)
{
try
{
Packet receivedPacket = Packet.ParseIncoming(buffer);
OnPacketReceived(new PacketReceivedEventArgs(receivedPacket));
switch (receivedPacket.Type)
{
case PacketType.Message:
OnMessageReceived(new MessageReceivedEventArgs(receivedPacket.Content));
MessageCallbackPacket packet = new MessageCallbackPacket(receivedPacket.SequenceNumber);
_udpClient.Send(packet.Bytes);
break;
case PacketType.CommandCallback:
if (MessageBuffer[receivedPacket.SequenceNumber] == null)
MessageBuffer[receivedPacket.SequenceNumber] = new PacketBuffer(receivedPacket);
else
MessageBuffer[receivedPacket.SequenceNumber].AddPacket(receivedPacket);
if (MessageBuffer[receivedPacket.SequenceNumber].IsComplete)
OnCommandCallback(new CommandCallbackEventArgs(MessageBuffer[receivedPacket.SequenceNumber].GetContent()));
break;
}
}
catch (ArgumentException) { }
catch (OverflowException) { }
catch (FormatException) { }
}
}
}
}
This is usually because you are not consuming your datagrams fast enough, so in-kernel socket buffer gets full and the network stack starts dropping newly arriving packets. Some points:
Increase the receive buffer on the socket,
Don't acquire locks on every iteration - read as much as you can, then put data into the queue,
Consider non-blocking approach instead of threads.

Unable to connect to other instances of the same program via TCP

I know this might have been asked a thousand times before, but I can't seem to find any specific information about my case.
I have a C# client program that has to connect to other instances of the client over a LAN. To connect one client to another, I use a TcpListener/TcpClient aproach. Both instances have a listener and are able to create a new client to connect/listen to one another (it is independant of which instance started the connection).
To create the listener, I use the following bit of code:
// In the constructor:
listener = new TcpListener(IPAddress.Any, 32842);
listenThread = new Thread((ThreadStart)ListenForConnections);
listenThread.Name = "ListenThread";
listenThread.IsBackground = true;
listenThread.Start();
// Listening for connections:
private void ListenForConnections()
{
listener.Start();
Console.WriteLine("Started listening for connections");
for (; ; )
{
if (listener.Pending())
{
using (TcpClient client = listener.AcceptTcpClient())
{
// My own layer over the TcpClient.
AsyncTCPClient other = new AsyncTCPClient(client);
Console.WriteLine("Connection from " + client.Client.RemoteEndPoint);
other.Received += DataReceived;
other.Exception += ExceptionOccurred;
connections.Add("Player", other);
other.Start();
}
}
else
{
Thread.Sleep(5);
}
}
}
To create and connect to another client, I use the following bit of code:
public void Connect(IPEndPoint other)
{
if (socket == null)
{
socket = new TcpClient(AddressFamily.InterNetwork);
socket.Client.ReceiveBufferSize = 2 * 1024 * 1024;
}
// Should force-close the socket after 5 seconds if it can't be closed automatically.
socket.LingerState = new LingerOption(true, 5);
socket.BeginConnect(other.Address, other.Port, ConnectionCallback, other);
IsConnecting = true;
}
The ConnectionCallback given as a parameter to BeginConnect looks like this:
private void ConnectionCallback(IAsyncResult result)
{
IsConnecting = false;
IsConnected = socket.Connected;
if (IsConnected)
{
IPEndPoint connectedTo = (IPEndPoint)result.AsyncState;
stream = socket.GetStream();
if (Connected != null)
{
Connected(this, null);
}
}
else
{
if (Exception != null)
{
RaiseException(new Exception("Unable to connect to host"));
}
}
}
However, everytime I get to the callback, the TcpClient failed to connect to the other instance and the Exception event is thrown. Now what I've found while searching around the internet (Google) is that it might have something to do with a firewall on either sides of the connection. But I've tested it with all firewalls off, so this can't be that.
I don't see Socket.EndConnect() being called in the callback.
See this in MSDN:
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.endconnect.aspx

How to make the process of scanning TCP ports faster?

I'm trying to asynchronously scan TCP ports. Since the open ports take just a few hundredths of milliseconds to complete they're fine, but when ports are closed I have to wait for the response.
So what happens is that I run the app and almost right away I see the port 80 to be open. Then I must wait like half a minute for all the other ports to get scanned.
EDIT. plus I would like to show the respond as it happens, with out waiting for other ports to be checked.
How to make this faster?
private void btnStart_Click(object sender, EventArgs e)
{
for (int port = 79; port < 90; port++)
{
ScanPort(port);
}
}
private void ScanPort(int port)
{
TcpClient client = new TcpClient();
client.BeginConnect(IPAddress.Parse("74.125.226.84"), port, new AsyncCallback(CallBack), client);
}
private void CallBack(IAsyncResult result)
{
bool connected = false;
using (TcpClient client = (TcpClient)result.AsyncState)
{
try
{
client.EndConnect(result);
connected = client.Connected;
}
catch (SocketException)
{
}
}
if (connected)
{
this.Invoke((MethodInvoker)delegate
{
txtDisplay.Text += "open2" + Environment.NewLine;
});
}
else
{
this.Invoke((MethodInvoker)delegate
{
txtDisplay.Text += "closed2" + Environment.NewLine;
});
}
}
You can use the WaitHandle BeginConnect returns to only wait so long.
using (var tcp = new TcpClient())
{
var ar = tcp.BeginConnect(host, port, null, null);
using (ar.AsyncWaitHandle)
{
//Wait 2 seconds for connection.
if (ar.AsyncWaitHandle.WaitOne(2000, false))
{
try
{
tcp.EndConnect(ar);
//Connect was successful.
}
catch
{
//EndConnect threw an exception.
//Most likely means the server refused the connection.
}
}
else
{
//Connection timed out.
}
}
}

Categories