I've decided to take a look at network messaging etc and my first port of call was UDP.
The problem i have is when i attempt to send a message. I'm trying to hit an IP on a specifc port, but the application errors with the error
"SocketException An existing connection was forcibly closed by the remote host".
Here is the code.
User ME = new User();
UdpClient MyUDPClient;
private void Form1_Load(object sender, EventArgs e)
{
ME.Username = Environment.UserName;
}
private void StartUDP_Click(object sender, EventArgs e)
{
CreateUDPClient();
}
private void CreateUDPClient()
{
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
int Port = int.Parse(txt_Port.Text);
ME.UserIP = new IPEndPoint(ip, Port);
break;
}
}
MyUDPClient = new UdpClient(ME.UserIP);
UDPListening();
}
public void UDPListening()
{
MyUDPClient.BeginReceive(ReceiveMessage, new object());
}
private void ReceiveMessage(IAsyncResult IAR)
{
byte[] B = MyUDPClient.EndReceive(IAR, ref ME.UserIP);
ProcessMSG(Encoding.ASCII.GetString(B));
UDPListening();
}
delegate void MessageDelegate(String MSG);
public void ProcessMSG(String M)
{
if (this.lbl_Messages.InvokeRequired)
{
MessageDelegate Del = new MessageDelegate(ProcessMSG);
this.Invoke(Del, M);
}
else
{
lbl_Messages.Text = M;
}
}
//Send Data to Another version of this program elsewhere.
private void btn_SendtoTarget_Click(object sender, EventArgs e)
{
IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse(txt_Send2IP.Text),int.Parse(txt_Send2Port.Text));
byte[] Message = Encoding.ASCII.GetBytes("TEST TEST TEST");
MyUDPClient.Send(Message, Message.Length, TargetIP);
}
}
thanks for the help.
Not sure if this helps but...
The Application is running on machine which is set to listen is on 192.168.0.25:5555
the Send is trying to send to Machine 192.168.0.50:10001
T
From further reading, I think my specific issue is the creation of the UDPclient object. It is created and is then listening on the ip 192.168.0.25:5555. When i attempt to send a message I'm attempting to use the same UDPClient but sending to a new IP. I'm getting the vibe that this is not the correct procedure and thus its trying to close the previous down??? I'm sure someone can comfirm this. So that would suggest to me that to have effective UDP networking (UP and Down) i'd need to have a UDPclient receiving and a second UDP to be able to send (which is dynamic to each target address i want to hit). Once again this is all guess work, and if i have this i hope someone could provide some pointers.
Several problems above.
Don't use ME in C#, it is this. Me is VB. The code above would not compile, as written, if using C#, since you left out your User() class you define as ME. I am not sure why you think you need that, since all it seems to hold is UserIP and UserName. The IP is part of a Socket, so you should just use that if you ever needed it:
IPAddress ip = IPAddress.Parse(socket.RemoteEndPoint);
And UserName could be made a global string variable - doesn't have to be part of a class.
Maybe I'm being nitpicky, but I didn't see where it was required to have either of those variables in the User() object like that and just mucked things up, for me, trying to decipher the code.
Always define your Socket, connect to it, then do your .Send(). You are missing the first 2 steps in your button click - you just do your .Send(). UdpClient is not a Socket, and I think it's better to do this as a Socket and define your connection type later. I think you could be right that you are trying to do your .Send() using the UdpClient you defined as your listener. Don't use the same object for your send and your listening! Normally you would, but you have 2 different addresses and ports for each event.
Don't use a foreach in your CreateUDPClient() function to get your IPAddress to assign to your IPEndPoint. You already knew your IP. Assign it directly. It's wasting processing time.
IPAddress ip = IPAddress.Parse("192.168.0.25");
IPEndPoint endPoint = new IPEndPoint(ip, port);
If you only had the host name, you would do:
string hostName = "MyComputerName";
int port = 5555; // or int.Parse(txt_Port.Text); ???
IPHostEntry hostEntry = Dns.GetHostAddresses(hostName);
IPEndPoint endPoint = new IPEndPoint(hostEntry[0], port);
Don't use Dns.GetHostEntry() -- if there's no reverse-lookup (PTR) record for that name, it will fail. Use Dns.GetHostAddresses(). And I have no idea why you think you needed the loop unless you have IPv6 addresses for the same host name you were providing. If not, just use [0] - it should be the first and only IP that will be returned that you'll be using if not using IPv6. But again, since you already have the IP, just plug that in - no need to do the lookup. It helps you eliminate Dns.GetHostName(), too - just use 192.168.0.25.
For your reference, MSDN has a procedure for your synchronous socket send/receive here:
https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx
and asynchronous socket send/receive here:
http://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx
Since I despise link only answers, and you seem to be mixing these 2 methods by using Send() and EndReceive(), respectively to the links above, I will endeavor to describe its contents succinctly and help fix your code:
Basically they say to use a StateObject class, instead of the global variable MyUDPClient you have:
public class StateObject
{
public byte[] buffer = new byte[1024];
public Socket workSocket;
public StringBuilder sb = new StringBuilder();
}
You would create a socket and add it to that. Buffer serves as a way to tell the Receive() or EndReceive() the size of the chunk you want to read back from the response at one time, and sb will serve as a placeholder for the response.
It looks like you have a lot going on here: a SendtoTarget_Click to do a one-off test from the form, and your listener. Your SendtoTarget button does a synchronous send, your StartUDP_Click() does an asynchronous receive.
You would change your SendtoTarget_Click() event to be this (which never defined your socket, before, and you must connect to it before sending):
private void btn_SendtoTarget_Click(object sender, EventArgs e)
{
IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse(txt_Send2IP.Text),int.Parse(txt_Send2Port.Text));
byte[] Message = Encoding.ASCII.GetBytes("TEST TEST TEST");
// Create a UDP socket.
Socket sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Udp);
try
{
// Connect to the remote endpoint.
sender.Connect(TargetIP);
// Send message -- already contains the endpoint so no need to
// specify again
sender.Send(Message, 0, Message.Length, SocketFlags.None);
sender.Close();
}
catch (Exception)
{
// do something here...
}
}
For your listener, you can do:
private void CreateUDPClient()
{
IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse("192.168.0.25"), 5555);
// Create a UDP socket.
Socket receiver = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Udp);
try {
// Create the state object.
StateObject state = new StateObject();
state.workSocket = receiver;
// Begin receiving the data from the remote device.
receiver.BeginReceive(state.buffer, 0, 256, 0,
new AsyncCallback(ReceiveMessage), state);
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
and your function called ReceiveMessage(), does this:
private void ReceiveMessage(IAsyncResult IAR)
{
string response = String.Empty;
try {
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject) IAR.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(IAR);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, 256, 0,
new AsyncCallback(ReceiveCallback), state);
} else {
// All the data has arrived; put it in response.
if (state.sb.Length > 1) {
response = state.sb.ToString();
}
// Signal that all bytes have been received.
client.Close();
}
ProcessMSG(response);
CreateUDPClient(); // personally, I would re-create than calling BeginReceive directly
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
Did my best to integrate your code with MSDN's in a way that should work. You might be able to get away with assigning that socket to the StateObject and calling BeginReceive() on it, again - not sure. But don't re-use the UdpClient object like that. Use the StateObject class like on MSDN and use it ONLY as your listener.
Related
As you can see in the code below I'm calling connect with an IP and port.
s.EndConnect(ar) is throwing ObjectDisposedException if the server is not running. Now if this happens I want to wait 5 seconds and retry. The problem is catching it in the ConnectCallback and calling itself doesn't work since the object IAsyncResult ar is disposed? I'm not storing the IP and port globally.
Now obviously I can store them globally and fix it that way, but I'm wondering if there's something else to fix this. Since I don't need the IP and port anywhere else storing them globally seems unnecessary.
Socket s;
public ClientSettings()
{
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void Connect(string IP, int port)
{
/* Simple connection method */
try
{
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(IP), port);
s.BeginConnect(ep, new AsyncCallback(ConnectCallback), s);
}
catch { }
}
void ConnectCallback(IAsyncResult ar)
{
s.EndConnect(ar);
connected = true;
byte[] buffer = new byte[8192];
s.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), buffer);
}
You're using outdated APIs. Use await with Socket and the problem goes away at much better code quality.
Or, use synchronous IO. This is appropriate if there will only be a few dozen connections at a time. This results in even easier code.
Alternatively, make IP and port instance variables. No need for globals.
I'm new with socket and trying to write a Client-Server application
My applicationhas those two main methods :
SERVER running on separate Thread :
public void socketListener()
{
byte[] StreamMessage = new byte[9632];
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndPoint =new IPEndPoint(IPAddress.Any , ControlLayer.GlobalParam.PEER2PEER_PORT);
listener.Bind(localEndPoint);
listener.Listen(10);
while (true)
{
Socket Handler = listener.Accept();
//int ByteRec = Handler.Receive(StreamMessage);
int MessageLength;
MessageLength = Handler.Receive(StreamMessage, 0, StreamMessage.Length, SocketFlags.None);
//return MessageLength;
// string message = System.Text.Encoding.Default.GetString(StreamMessage);
string message = System.Text.Encoding.UTF8.GetString(StreamMessage);
OnDataRecievedFromRemotePeer(this, message, "TcpServer");//send data to screen
Task.Run(() => { ParseMessage(message, Handler); });
}
}
once data arrives I prase it collect data and send it using Client
CLIENT :
public void Write(string message)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CreateClient), message);
}
private void CreateClient(object message)
{
try
{
peerClient = new TcpClient();
peerClient.Connect(remoteIP, 6001/*TODO remove this */);
netStream = peerClient.GetStream();//<- Exception
StreamWriter sw = new StreamWriter(netStream);
sw.Write((string)(message));
netStream.Close();
peerClient.Close();
}
catch(Exception ex)
{
//TODO :
}
}
Each station is symmetrical and have those two methods
I can tell that the server is working and accepting socket and data
but once I want to respond back I get exception in the Line marked in the CreateClient
stream was not writable and when looking on the netStream it is written that I have ObjectDisposed Exception .
What can be the cause of that ?
Also please inform me if more code is needed
You have a classical race here between the server closing the connection before the client has processed the response of the server.
TCP is a "polite" protocol, which means that you can not perform a fire and forget action on the server. The connection needs to be alive on both ends until both sides have processed all messages. Thus either the client needs to send an acknowledge/logout, so that the server can close the connection or at least the server has to wait x seconds until closing it.
Is it possible to identify an earlier UDP client without keeping the socket open? I want to link an integer ID to each unique client, but I don't want to keep any additional threads open.
//Receive (Server)
private static Int32 port = 11000;
private static UdpClient udpClient = new UdpClient(port);
public static void receive_threaded()
{
Thread t = new Thread(() =>
{
while (true)
{
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);
byte[] content = udpClient.Receive(ref remoteIPEndPoint);
if (content.Length > 0)
{
string message = Encoding.UTF8.GetString(content);
if (action_message_receive != null) action_message_receive(String.Format("Recv({0}): {1}", remoteIPEndPoint.Port, message));
parseMessage(message);
}
}
});
t.Start();
}
//Send (Client)
private static void send_message(string ip, string message)
{
byte[] packetData = System.Text.UTF8Encoding.UTF8.GetBytes(message);
int port = 11000;
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ip), port);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
client.SendTo(packetData, ep);
if (action_message_send != null) action_message_send("Send: " + message);
}
A client can request a (temporary) userID from the server, and the server will add it to it's database and notify the client when it's done doing that. However, I can't have the client send it's own userID when it's making requests because any memory altering application would mean a 'hacker' could gain access to other user's stuff.
Since the socket doesn't stay open, the IPEndPoint.Port changes every time the client sends something to the server, so I can't keep track of it with that. I could get it done by creating a username/pass on a userID request and having those sent on every single request involving the userID thereafter, but that would be silly.
So is there any way to do this without keeping a thread open for each client? I'm probably doing something really weird here because UDP is supposed to be a one way street, but I'm here to learn so I just had to ask.
You will need to introduce some sort of unique identifier chosen by the server and sent to the client for it to "behave and send it back for identification purposes". A random long integer should suffice.
UDP has neither connections nor identification/authentication mechanisms. If you want those, use TCP (but those can be bruteforced also...)
Hi i have a disconnect button click event in my SERVER application as follows.Before it dc, it will alert other clients by sending a "/exit" command.After that it will shutdown its connection.
private void stopButton_Click(object sender, EventArgs e)
{
byte[] exit_command = Encoding.ASCII.GetBytes("/exit");
g_server_conn.BeginSend(exit_command, 0, exit_command.Length, SocketFlags.None, new AsyncCallback(Send), g_server_conn);
g_server_conn.Shutdown(SocketShutdown.Both);
g_server_conn.Close();
}
The problem is that the server is executing Socket.BeginRecieve() method all the time. How do we tell the begin recieve method to stop its operation so that i can close properly.
private void Accept(IAsyncResult iar)
{
Socket winsock = (Socket)iar.AsyncState;
g_server_conn = winsock.EndAccept(iar);
//Function that exchanges names of each other
NewClient(g_server_conn);
Socket server_conn = g_server_conn;
chat_msg = new byte[1024];
server_conn.BeginReceive(chat_msg, 0, chat_msg.Length, SocketFlags.None, new AsyncCallback(Recieve), server_conn);
}
private void Recieve(IAsyncResult iar)
{
Socket server_conn = (Socket)iar.AsyncState;
server_conn.EndReceive(iar);
//If clients shutdown connection,Server recieves /exit command
if (Encoding.ASCII.GetString(chat_msg, 0, chat_msg.Length) == "/exit")
{
g_server_conn.Shutdown(SocketShutdown.Both);
g_server_conn.Close();
return;
}
SetLabel(client_name, chatListBox);
SetLabel(Encoding.ASCII.GetString(chat_msg), chatListBox);
chat_msg = new byte[1024];
server_conn.BeginReceive(chat_msg, 0, chat_msg.Length, SocketFlags.None, new AsyncCallback(Recieve), server_conn);
}
You should use the IAsyncResult returned by the BeginXXX methods. IIRC, you can dispose of the WaitHandle.
Does the clients realy need to know why the server closed the connection(You seem to send a disconnect message with no reason information anyways,)? It seems your just sending a extra message to the clients to disconnect them.
You can just disconnect all the clients, and they will recive a close socket message, this will on the client side show the connection being closed.
On a side note, there is no point in converting the recived string so many times, convert it once from byte array to string and your done :).
Personaly the order i would do it is:
1)Set a global bool, that we are no longer accepting new clients ( IE if a new client tries to connect in this time, i would not accept it)
2)Go over the client list an and disconnect them
3)Shut downt he lister.
I have an embedded Ethernet interface (Lantronix XPort) that responds to a UDP broadcast with its identifying information.
I am able to multicast the "magic packet" and datagrams are received by the listener correctly, however I also need to find out what IP Address send that response datagram. If it were TCP, I would do socket.RemoteEndPoint, but that throws an exception when applied to a UDP socket.
public class Program
{
public static void Main(string[] args)
{
// magic packet
byte[] magicPacket = new byte[4] { 0, 0, 0, 0xf6 };
// set up listener for response
Socket sendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// EDIT: Also, had to add this to for it to broadcast correctly
sendSocket.EnableBroadcast = true;
IPEndPoint listen_ep = new IPEndPoint(IPAddress.Any, 0);
sendSocket.Bind(listen_ep);
// set up broadcast message
EndPoint send_ep = new IPEndPoint(IPAddress.Parse("192.168.255.255"), 30718);
sendSocket.SendTo(magicPacket, magicPacket.Length, SocketFlags.None, send_ep);
DateTime dtStart = DateTime.Now;
while (true)
{
if (sendSocket.Available > 0)
{
byte[] data = new byte[2048];
// throws SocketException
//IPEndPoint ip = sendSocket.RemoteEndPoint as IPEndPoint;
sendSocket.Receive(data, SocketFlags.None);
if (data.Length > 4)
{
PrintDevice(data);
}
}
if (DateTime.Now > dtStart.AddSeconds(5))
{
break;
}
Console.WriteLine(".");
Thread.Sleep(100);
}
// wait for keypress to quit
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
Any thoughts? Is there a better strategy to reading the response datagrams that would let me ascertain the Remote IP Address?
EDIT:
As is typical, the minute I post on SO, a moment of clarity hits me.
Turns out I can just do this:
EndPoint remote_ep = new IPEndPoint(IPAddress.Any, 0);
// Use ReceiveFrom instead of Receieve
//sendSocket.Receive(data, SocketFlags.None);
sendSocket.ReceiveFrom(data, ref remote_ep);
And remote_ep now contains the remote endpoint information!
Take a look at ReceiveFrom instead of Receive, it will let you pass in a reference to an Endpoint.
What about Asynchronous socket?I didn't find any way to get the remote IP address. (Asynchronous method ReceiveFromAsync is my only option in wp8)
EndPoint remote_ep = new IPEndPoint(IPAddress.Any, 0); // Use ReceiveFrom instead of
sendSocket.Receive(data, SocketFlags.None);
sendSocket.ReceiveFrom(data, ref remote_ep);
i think it works for IP but it fails for port number
if you would notice
try chaging 0 to something else like 6530 4expl
it system will would generate it's random port number
Any ideas to why is it ?
P.S. Any ideas how can i change my user name here .... ?
FOUND IT : the abstract class only needed for representation of port it is in value not out
since there's no bind done before hand this operation ref EndPoint needed to represent the sender. Meaning that it is there to show senders port and IP not to specify from where to get the communication. And EndPoint instantiation is really just a formality seems like it is overriden by system with senders address anyway. I think it has to do somethign with the way UDP protocol works.
But all in all the ref EndPoint is there only shows where u got the packet from and only it does not specify where u want u'r commuicatino to be from.