Save connected Socket in Dictionary - c#

I'm trying to save a connected socket in a dictionary so my API doesn't have to create a new connection every time. My problem is that the socket gets disposed.
So when I call GetConnection() a second time socket.connected is false and socket.Available.Message is "Cannot access a disposed object. Object name: 'System.Net.Sockets.Socket'.".
public static class ModbusSocket
{
private static Dictionary<IPAddress, Socket> socketList;
public static Socket GetConnection(string server, int port)
{
if (socketList is null)
{
socketList = new Dictionary<IPAddress, Socket>();
}
IPAddress iPAddress = IPAddress.Parse(server);
if (socketList.ContainsKey(iPAddress))
{
var socket = socketList[iPAddress];
if (socket.Connected)
{
return socket;
}
else
{
socketList.Remove(iPAddress);
socket = new Socket(iPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipe = new IPEndPoint(iPAddress, port);
socket.Connect(ipe);
socketList.Add(iPAddress, socket);
return socket;
}
}
else
{
Socket socket = new Socket(iPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipe = new IPEndPoint(iPAddress, port);
socket.Connect(ipe);
socketList.Add(iPAddress, socket);
return socket;
}
}
}

OMG I found the issue...
I invoked it with using:
using (Socket s = ModbusSocket.GetConnection(hostIp, port))
{
var telegram = new Telegram();
telegram.Set(0, AddressConst.PositionWindow, 4);
var response = telegram.SendAndReceive(s);
var result = BitConverter.ToInt32(new byte[] { response.Byte19, response.Byte20, response.Byte21, response.Byte22 }, 0);
return result;
}

Related

c# socket connection with multi threading telnet

**i use c# this code socket connection with multi threading **
i need set time out to my socket connection telnet
string ip = "";
int port = 23;
string str = "";
IPAddress address = IPAddress.Parse(ip);
IPEndPoint ipEndPoint = new IPEndPoint(address, port);
Socket socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Connect((EndPoint)ipEndPoint);
try
{
byte[] numArray = new byte[1024];
while (socket.Connected) {
int count = socket.Receive(numArray);
str += Encoding.ASCII.GetString(numArray, 0, count);
Console.WriteLine(str);
}
socket.Close();
}
catch (ArgumentNullException ex)
{
}
You can either create a timer to do this or what I like to do is give the socket.connected a timeframe and base my connection of that. You'd obviously need to modify the time per your conditions, but this example has worked for me in the past.
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Connect using a timeout (5 seconds)
IAsyncResult result = socket.BeginConnect( iP, iPort, null, null );
bool success = result.AsyncWaitHandle.WaitOne( 5000, true );
if ( socket.Connected )
{
socket.EndConnect( result );
}
else
{
//Be sure to close socket
socket.Close();
throw new ApplicationException("Failed to connect the server. Try again.");
}
I saw another example someone else did with timer, but I have not personally used this, so whichever you are more comfortable with. start a timer (timer_connection), if time is up, check whether socket connection is connected (if(m_clientSocket.Connected)), if not, pop up timeout error
private void connect(string ipAdd,string port)
{
try
{
SocketAsyncEventArgs e=new SocketAsyncEventArgs();
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(serverIp);
int iPortNo = System.Convert.ToInt16(serverPort);
IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);
//m_clientSocket.
e.RemoteEndPoint = ipEnd;
e.UserToken = m_clientSocket;
e.Completed+=new EventHandler<SocketAsyncEventArgs>(e_Completed);
m_clientSocket.ConnectAsync(e);
if (timer_connection != null)
{
timer_connection.Dispose();
}
else
{
timer_connection = new Timer();
}
timer_connection.Interval = 2000;
timer_connection.Tick+=new EventHandler(timer_connection_Tick);
timer_connection.Start();
}
catch (SocketException se)
{
lb_connectStatus.Text = "Connection Failed";
MessageBox.Show(se.Message);
}
}
private void e_Completed(object sender,SocketAsyncEventArgs e)
{
lb_connectStatus.Text = "Connection Established";
WaitForServerData();
}
private void timer_connection_Tick(object sender, EventArgs e)
{
if (!m_clientSocket.Connected)
{
MessageBox.Show("Connection Timeout");
//m_clientSocket = null;
timer_connection.Stop();
}
}

How to end the loop on timeout, TCPServer Socket C#

I am creating a TCP Server/Client. As for this project, i need to only run this function for 60 seconds, and after that, it will terminate. Can someone guide me to fix this code?
public static void SendTCPServer(string content)
{
Stopwatch timer = new Stopwatch();
timer.Start();
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any,
8080);
Socket newsock = new
Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
newsock.Bind(ipep);
newsock.Listen(10);
while (timer.Elapsed.TotalSeconds < 60)
{
Console.WriteLine("Waiting for a client...");
Socket client = newsock.Accept();
IPEndPoint clientep =
(IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("Connected with {0} at port {1}",
clientep.Address, clientep.Port);
string welcome = content;
data = Encoding.ASCII.GetBytes(welcome);
client.Send(data, data.Length,
SocketFlags.None);
Console.WriteLine("Disconnected from {0}",
clientep.Address);
client.Close();
newsock.Close();
return;
}
timer.Stop();
//client.Close();
newsock.Close();
return;
}
You can use thread for this.
public class Parameters
{
public Socket _socket;
public string content;
}
//calling part
Thread listenerThread = new Thread(new ParameterizedThreadStart(SendTCPServer));
Socket newsock = new
Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
listenerThread.Start(new Parameters { _socket = newsock, content = "Welcome"
});
Thread.Sleep(60000);
newsock.Dispose();
//calling part end
public static void SendTCPServer(object obj)
{
try
{
Stopwatch timer = new Stopwatch();
timer.Start();
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any,
8080);
Parameters param = obj as Parameters;
Socket newsock = param._socket;
newsock.Bind(ipep);
newsock.Listen(10);
while (timer.Elapsed.TotalSeconds < 60)
{
Console.WriteLine("Waiting for a client...");
Socket client = newsock.Accept();
IPEndPoint clientep =
(IPEndPoint)client.RemoteEndPoint;
Console.WriteLine("Connected with {0} at port {1}",
clientep.Address, clientep.Port);
string welcome = param.content;
data = Encoding.ASCII.GetBytes(welcome);
client.Send(data, data.Length,
SocketFlags.None);
Console.WriteLine("Disconnected from {0}",
clientep.Address);
client.Close();
newsock.Close();
return;
}
timer.Stop();
//client.Close();
newsock.Close();
return;
}
catch (Exception ex)
{
}
}

Socket not receiving messages

When I use "127.0.0.1" on the same computer, it works just fine. If I try to use the server's public ip address, it doesn't work (actually I get a socket error). If I make it ipaddress.any it doesn't give an error, but it doesn't work, either. I thought maybe it's because I'm on the same computer, so I put the server on my desktop and client on my laptop, and I connected my laptop to my phone's hotspot so the ipaddress is different. It still doesn't work. The message gets sent, but never received. What am I doing wrong?
struct DataPacket
{
public IPEndPoint destination;
public byte[] data;
public DataPacket(IPEndPoint destination, byte[] data)
{
this.destination = destination;
this.data = data;
}
}
AsyncPriorityQueue<DataPacket> queuedReceiveData = new AsyncPriorityQueue<DataPacket>(NetworkConstants.MAX_PLAYERS_PER_SERVER, false);
Socket sck;
IPEndPoint ipEndPoint;
bool listening = true;
bool processing = true;
void Start()
{
sck = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
#if SERVER
ipEndPoint = new IPEndPoint(IPAddress.Any, NetworkConstants.SERVER_PORT);
sck.Bind(ipEndPoint);
#else
ipEndPoint = new IPEndPoint(IPAddress.Parse(NetworkConstants.SERVER_IP), NetworkConstants.SERVER_PORT);
EndPoint ep = new IPEndPoint(IPAddress.Any, 0); // doesn't work at all
//EndPoint ep = new IPEndPoint(IPAddress.Parse(NetworkConstants.SERVER_IP), 0); // says requested address is not valid in its context
//EndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 0); // works only on same computer
sck.Bind(ep);
#endif
new Thread(() => ListenForData()).Start();
new Thread(() => ProcessData()).Start();
#if !SERVER
SerializeCompact.BitStream bs = new SerializeCompact.BitStream();
bs.Write(Headers.Connect, minHeader, maxHeader);
SendData(bs.GetByteArray());
#endif
}
void OnDestroy()
{
listening = false;
processing = false;
sck.Close();
}
public void SendData(byte[] data)
{
var packet = queuedSendData.Dequeue();
sck.SendTo(data, 0, data.Length, SocketFlags.None, ipEndPoint);
print("message sent to server");
}
public void SendDataTo(byte[] data, IPEndPoint endPoint)
{
var packet = queuedSendData.Dequeue();
sck.SendTo(data, 0, data.Length, SocketFlags.None, endPoint);
print("message sent to client");
}
void ListenForData()
{
while (listening)
{
EndPoint endPoint = ipEndPoint;
byte[] buffer = new byte[1024];
int rec = sck.ReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref endPoint);
Array.Resize(ref buffer, rec);
queuedReceiveData.Enqueue(new DataPacket((IPEndPoint) endPoint, buffer), 0);
print("received message");
ProcessData(buffer);
}
}
void ProcessData()
{
while (processing)
{
var rcv = queuedReceiveData.Dequeue(); // blocks until an item can be dequeued
byte[] data = rcv.data;
IPEndPoint ep = rcv.destination;
// process data...
}
}

Client And Server Socket Connection using C#

I created two projects one with client and other with server to exchange text between both of them;on same computer i run those exe.
MY Client Side Connection Code connection looked :
using (SocketClient sa = new SocketClient(host, port))
{
sa.Connect();
Console.WriteLine(sa.SendReceive("Message #" + i.ToString()));
}
sa.Disconnect();
while socketclient is my class which contain these methods and constructor:
internal SocketClient(String hostName, Int32 port)
{
IPHostEntry host = Dns.GetHostEntry(hostName);
IPAddress[] addressList = host.AddressList;
this.hostEndPoint = new IPEndPoint(addressList[addressList.Length - 1], port);
this.clientSocket = new Socket(this.hostEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
internal void Connect()
{
SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs();
connectArgs.UserToken = this.clientSocket;
connectArgs.RemoteEndPoint = this.hostEndPoint;
connectArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnect);
clientSocket.ConnectAsync(connectArgs);
autoConnectEvent.WaitOne();
SocketError errorCode = connectArgs.SocketError;
if (errorCode != SocketError.Success)
{
throw new SocketException((Int32)errorCode);
}
}
internal void Disconnect()
{
clientSocket.Disconnect(false);
}
private void OnConnect(object sender, SocketAsyncEventArgs e)
{
autoConnectEvent.Set();
this.connected = (e.SocketError == SocketError.Success);
}
internal String SendReceive(String message)
{
if (this.connected)
{
Byte[] sendBuffer = Encoding.ASCII.GetBytes(message);
SocketAsyncEventArgs completeArgs = new SocketAsyncEventArgs();
completeArgs.SetBuffer(sendBuffer, 0, sendBuffer.Length);
completeArgs.UserToken = this.clientSocket;
completeArgs.RemoteEndPoint = this.hostEndPoint;
completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);
clientSocket.SendAsync(completeArgs);
AutoResetEvent.WaitAll(autoSendReceiveEvents);
return Encoding.ASCII.GetString(completeArgs.Buffer, completeArgs.Offset,completeArgs.BytesTransferred);
}
else
{
throw new SocketException((Int32)SocketError.NotConnected);
}
}
while on server side code looks like that:
SocketListener sl = new SocketListener(numConnections, bufferSize);
sl.Start(port);
Console.WriteLine("Server listening on port {0}.
Press any key to terminate the server process...", port);
Console.Read();
sl.Stop();
Socket listener is my class which contain this method and constructor :
internal SocketListener(Int32 numConnections, Int32 bufferSize)
{
this.numConnectedSockets = 0;
this.numConnections = numConnections;
this.bufferSize = bufferSize;
this.readWritePool = new SocketAsyncEventArgsPool(numConnections);
this.semaphoreAcceptedClients = new Semaphore(numConnections, numConnections);
for (Int32 i = 0; i < this.numConnections; i++)
{
SocketAsyncEventArgs readWriteEventArg = new SocketAsyncEventArgs();
readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs> (OnIOCompleted);
readWriteEventArg.SetBuffer(new Byte[this.bufferSize], 0, this.bufferSize);
this.readWritePool.Push(readWriteEventArg);
}
}
internal void Start(Int32 port)
{
IPAddress[] addressList = Dns.GetHostEntry(Environment.MachineName).AddressList;
IPEndPoint localEndPoint = new IPEndPoint(addressList[addressList.Length - 1], port);
this.listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this.listenSocket.ReceiveBufferSize = this.bufferSize;
this.listenSocket.SendBufferSize = this.bufferSize;
if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6)
{
this.listenSocket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
this.listenSocket.Bind(new IPEndPoint(IPAddress.IPv6Any, localEndPoint.Port));
}
else
{
this.listenSocket.Bind(localEndPoint);
}
this.listenSocket.Listen(this.numConnections);
this.StartAccept(null);
mutex.WaitOne();
}
I have already port forward of my router because of server side exe which didn't listen without port forwarding.
it is working fine with send and receive on same pc and same port at home.
While when i try to run both of codes exe on my office computer it throws exception at following line:
Exception thrown by socket
Could any one guide me whats the problem and how to resolve it ?
Thanks
Have you tried temporary disable your Windows firewall ?

Send socket before closing

I have this code:
public static List<Socket> samp = new List<Socket>();
Socket connection/etc in form load..
IPHostEntry host = null;
Socket sock;
host = Dns.GetHostEntry(sending ip..);
foreach (IPAddress address in host.AddressList)
{
IPEndPoint ipe = new IPEndPoint(address, 7777);
sock = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(ipe);
if (sock.Connected)
{
sock.SendTo(Encoding.UTF8.GetBytes("App starts"), ipe);
samp.Add(sock);
}
}
In form closing:
if (samp.Count > 0)
{
foreach (Socket socket in samp)
{
socket.Send(Encoding.UTF8.GetBytes("App closing"));
socket.Close();
}
}
And i'm getting error:
Cannot access a disposed object. Object name: 'System.Net.Sockets.Socket'
Thanks in advance!
P.S looks like socket.Close() works, but socket.Send nope :(

Categories