Issue while writing ModbusClient and ModbusServer together - c#

About the Code
I am using EasyModbus Nuget in C# Window Form Application. I am trying to fetch the changed Holding Register's Address Value through RTU(Real Time Update) using ModbusServer.
Below code connect to server.
void Connect() {
ModbusClient client = null;
client = new ModbusClient("IP Address", 502);
client.Connect();
}
Below code fetches the value of address given below Holding Register.
client.ReadHoldingRegisters(10001, 1);
So far, everything works perfectly.
I was reading about reading about Real Time Updates in EasyModbus. I found this link that can send the changed value of holding register automatically to the even handler.
Now, I have below code:
void Connect() {
ModbusServer ser = new ModbusServer();
ser.Port = Convert.ToInt32(Settings.Default.Port);
ser.Listen();
ser.HoldingRegistersChanged += Ser_HoldingRegistersChanged;
ModbusClient client = null;
client = new ModbusClient("IP Address", 502);
client.Connect();
}
private void Ser_HoldingRegistersChanged(int register, int numberOfRegisters)
{
}
When I run it, I get below error.
Only one usage of each socket address (protocol/network address/port)
is normally permitted
This error is occurring because I added the ModbusServer code.
Can you please suggest why this is happening?

Your problem isn't so serious and your main problem in this line
ser.Listen();
because your previous server socket is still in bound.
let's take a looks when a listen socket is in bound ?
obvious reason is when your listening socket send/receive packets but in rare conditions it happens when OS is NOT in ideal condition(100 % cpu usage and etc) then Releasing server socket might takes a minute to be released. in this condition when you run your server again the exception
Only one usage of each socket address (protocol/network address/port)
is normally permitted
happens.because , as i said before the previous server socket was not released yet.
Solution is
using different ports for different server sockets
or
use only one server socket which is initiated only once and check if it's connected or not.
// create the socket
public static Socket listenSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
// bind the listening socket to the port
IPAddress hostIP = (Dns.Resolve(IPAddress.Any.ToString())).AddressList[0];
IPEndPoint ep = new IPEndPoint(hostIP, port);
if(!listenSocket.IsBound){
listenSocket.Bind(ep);
// start listening
listenSocket.Listen(backlog);
}
// connect client
ModbusClient client = null;
client = new ModbusClient(hostIP , port);
client.Connect();

It seems you already have a server on the port and you try to add one more. Try the code below:
public partial class Form1 : Form
{
private int register = 0;
private readonly int port = 502;
private readonly List<ModbusServer> servers = new List<ModbusServer>();
private readonly List<ModbusClient> clients = new List<ModbusClient>();
public Form1()
{
InitializeComponent();
AppDomain.CurrentDomain.FirstChanceException +=
(sender, e) => MessageBox.Show(e.Exception.Message);
}
private void Foo(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message);
}
private void Ser_HoldingRegistersChanged(int register, int numberOfRegisters) =>
MessageBox.Show($"register: {register}, numberOfRegisters: {numberOfRegisters}");
private void AddServer_Click(object sender, EventArgs e) =>
AddServerMethod();
private void AddClient_Click(object sender, EventArgs e) =>
AddClientMethod();
private void AddServerMethod()
{
var server = new ModbusServer { Port = port };
server.Listen();
server.HoldingRegistersChanged += Ser_HoldingRegistersChanged;
servers.Add(server);
MessageBox.Show("Server added.");
server.holdingRegisters[0] = 11; // register is changed, but no event is fired
}
private void AddClientMethod()
{
var client = new ModbusClient("127.0.0.1", port);
client.Connect();
clients.Add(client);
MessageBox.Show("Client added.");
client.WriteSingleRegister(register++, 11); // event is fired
}
}
If you click AddServer more than once you get the error you described. Btw, if you click AddClient before AddServer you get another error. Add one server and then add any number of clients. Each client writes a holding register and related event is fired with a message like this:

Related

Listen to message from an IP from another machine

I am trying to send a message to Unity through UDP. The machine that sends the message has IP as 192.16.14.1 and port as 3034. How do I enter these two inside of Unity application? I have found a code to listen for UDP messages but I cannot set the IP address here. Also the Unity application should be running at all times even if the message from another machine is sent or not.
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine;
public class UDP_Listen : MonoBehaviour
{
UdpClient clientData;
int portData = 3034;
public int receiveBufferSize = 120000;
public bool showDebug = false;
IPEndPoint ipEndPointData;
private object obj = null;
private System.AsyncCallback AC;
byte[] receivedBytes;
void Start()
{
InitializeUDPListener();
}
public void InitializeUDPListener()
{
ipEndPointData = new IPEndPoint(IPAddress.Any, portData);
clientData = new UdpClient();
clientData.Client.ReceiveBufferSize = receiveBufferSize;
clientData.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true);
clientData.ExclusiveAddressUse = false;
clientData.EnableBroadcast = true;
clientData.Client.Bind(ipEndPointData);
clientData.DontFragment = true;
if (showDebug) Debug.Log("BufSize: " + clientData.Client.ReceiveBufferSize);
AC = new System.AsyncCallback(ReceivedUDPPacket);
clientData.BeginReceive(AC, obj);
Debug.Log("UDP - Start Receiving..");
}
void ReceivedUDPPacket(System.IAsyncResult result)
{
//stopwatch.Start();
receivedBytes = clientData.EndReceive(result, ref ipEndPointData);
ParsePacket();
clientData.BeginReceive(AC, obj);
//stopwatch.Stop();
//Debug.Log(stopwatch.ElapsedTicks);
//stopwatch.Reset();
} // ReceiveCallBack
void ParsePacket()
{
// work with receivedBytes
Debug.Log("receivedBytes len = " + receivedBytes.Length);
}
void OnDestroy()
{
if (clientData != null)
{
clientData.Close();
}
}
}
If the Unity application is to be receiving the messages constantly, it needs to be something like:
UdpClient listener = new UdpClient(11000);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Parse("192.16.14.1"), 3034);
while (true)
{
byte[] bytes = listener.Receive(ref groupEP);
}
This should read only calls from the specific IP, not sure which port you want the UDPClient to read out from (specified in the UDPClient constructor) but you can set this to whatever you need it to be.
So there are two different things:
You want to define the receiving local port you Bind your socket to
You want to define the expected sending remote ip + port you want to Receive from
Currently you are using the very same one
ipEndPointData = new IPEndPoint(IPAddress.Any, portData);
for both! (Fun fact: As a side effect by using always the same field you basically allow any sender but are then bond to that specific sender from this moment on)
Actually a lot of things you configure there are the default values anyway so here is more or less what I would do
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
public class UDP_Listen : MonoBehaviour
{
public ushort localReceiverPort = 3034;
public string senderIP = "192.168.111.1";
public ushort remoteSenderPort = 3034;
public bool showDebug = false;
// Thread-safe Queue to handle enqueued actions in the Unity main thread
private readonly ConcurrentQueue<Action> mainThreadActions = new ConcurrentQueue<Action>();
private Thread udpListenerThread;
private void Start()
{
// do your things completely asynchronous in a background thread
udpListenerThread = new Thread(UDPListenerThread);
udpListenerThread.Start();
}
private void Update()
{
// in the Unity main thread work off the actions
while (mainThreadActions.TryDequeue(out var action))
{
action?.Invoke();
}
}
private void UDPListenerThread()
{
UdpClient udpClient = null;
try
{
// local end point listens on any local IP
var localEndpoint = new IPEndPoint(IPAddress.Any, localReceiverPort);
udpClient = new UdpClient(localEndpoint);
if (showDebug)
{
Debug.Log("BufSize: " + clientData.Client.ReceiveBufferSize);
}
Debug.Log("UDP - Start Receiving..");
// endless loop -> ok since in a thread and containing blocking call(s)
while (true)
{
// remote sender endpoint -> listens only to specific IP
var expectedSenderEndpoint = new IPEndPoint(IPAddress.Parse(senderIP), remoteSenderPort);
// blocking call - but doesn't matter since this is a thread
var receivedBytes = udpClient.Receive(ref expectedSenderEndpoint);
// parse the bytes here
// do any expensive work while still on a background thread
mainThreadActions.Enqueue(() =>
{
// Put anything in here that is required to happen in the Unity main thread
// so basically anything using GameObject, Transform, etc
});
}
}
// thrown for "Abort"
catch (ThreadAbortException)
{
Debug.Log("UDP Listener terminated");
}
// Catch but Log any other exception
catch (Exception e)
{
Debug.LogException(e);
}
// This is run even if an exception happend
finally
{
// either way dispose the UDP client
udpClient?.Dispose();
}
}
private void OnDestroy()
{
udpListenerThread?.Abort();
}
}
I'm sure the same can be done also using the BeginReceive/EndReceive or task based alternatives but since it is going to run endless anyway I personally find a thread often easier to read and maintain.
I think you got it backwards. This code you shared is for, like you said, listen UDP protocol on desired port. This piece of code needs to be inside your "server". By server try to understand that as the receiving side.
on your shared method InitializeUDPListener(); we have this piece:
ipEndPointData = new IPEndPoint(IPAddress.Any, portData);
this means you are initializing your udp socket to listen for ANY ip adresses at the given port. That said, you have your server ready to go, what you need to do is setup the client side, the one who sends the message.
here some example:
public string serverIp = "127.0.0.1"; // your server ip, this one is sending to local host
public int serverPort = 28500; // your server port
public void ClientSendMessage()
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress broadcast = IPAddress.Parse(serverIp);
byte[] sendbuf = Encoding.ASCII.GetBytes("THIS IS A MESSAGE FROM CLIENT!");
IPEndPoint ep = new IPEndPoint(broadcast, serverPort);
s.SendTo(sendbuf, ep);
}
I encourage you to read about UDP/TCP protocols before using them. MS has documentation with details.
here some links:
TCP
UDP
Sockets

Winsock server/client application in c#

I'm working to make a Client/Server Application in C# using winsock Control. I done every thing in that but i stuck the place of sending data from client to server. In my program server always listen the client using the ip and port. I send the data from the client to server.
1)When click the Listen button on the server form it open the server where client is connect.
2)In Client form 1st i click the connect button for that the server is connected Gives an message (Connect Event: ip) for this message we easly know that the client is connected to the server.
3)Then we enter some data in the Send Data text Box then click Send Button to send the data to server and also save in client.
Code Below:
SERVER:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using System.Net.Sockets;
namespace Server
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
const string DEFAULT_SERVER = "ip";
const int DEFAULT_PORT = 120;
System.Net.Sockets.Socket serverSocket;
System.Net.Sockets.SocketInformation serverSocketInfo;
public string Startup()
{
IPHostEntry hostInfo = Dns.GetHostByName(DEFAULT_SERVER);
IPAddress serverAddr = hostInfo.AddressList[0];
var serverEndPoint = new IPEndPoint(serverAddr, DEFAULT_PORT);
serverSocket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
serverSocket.Bind(serverEndPoint);
return serverSocket.LocalEndPoint.ToString();
}
public string Listen()
{
int backlog = 0;
try
{
serverSocket.Listen(backlog);
return "Server listening";
}
catch (Exception ex)
{
return "Failed to listen" + ex.ToString();
}
}
public string ReceiveData()
{
System.Net.Sockets.Socket receiveSocket;
byte[] buffer = new byte[256];
receiveSocket = serverSocket.Accept();
var bytesrecd = receiveSocket.Receive(buffer);
receiveSocket.Close();
System.Text.Encoding encoding = System.Text.Encoding.UTF8;
return encoding.GetString(buffer);
}
private void Listen_Click(object sender, EventArgs e)
{
string serverInfo = Startup();
textBox1.Text = "Server started at:" + serverInfo;
serverInfo = Listen();
textBox1.Text = serverInfo;
//string datatosend = Console.ReadLine();
//SendData(datatosend);
serverInfo = ReceiveData();
textBox1.Text = serverInfo;
//Console.ReadLine();
}
private void winsock_DataArrival(object sender, AxMSWinsockLib.DMSWinsockControlEvents_DataArrivalEvent e)
{
ReceiveData();
Listen();
}
private void winsock_ConnectEvent(object sender, EventArgs e)
{
Listen();
}
}
}
This all are work perfectly But here my problem is that i get data form the client to server at only one time. When i send data again from the client to the server its not working and gives me some Message like
Additional information: Only one usage of each socket address
(protocol/network address/port) is normally permitted
In the server form
serverSocket.Bind(serverEndPoint);
Please someone help me to solve my problem.
Thank you.
Try this. It helps you
delegate void AddTextCallback(string text);
public Form1()
{
InitializeComponent();
}
private void ButtonConnected_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ServerHandler));
}
private void ServerHandler(object state)
{
TcpListener _listner = new TcpListener(IPAddress.Parse("12.2.54.658"), 145);
_listner.Start();
AddText("Server started - Listening on port 145");
Socket _sock = _listner.AcceptSocket();
//AddText("User from IP " + _sock.RemoteEndPoint);
while (_sock.Connected)
{
byte[] _Buffer = new byte[1024];
int _DataReceived = _sock.Receive(_Buffer);
if (_DataReceived == 0)
{
break;
}
AddText("Message Received...");
string _Message = Encoding.ASCII.GetString(_Buffer);
AddText(_Message);
}
_sock.Close();
AddText("Client Disconnected.");
_listner.Stop();
AddText("Server Stop.");
}
private void AddText(string text)
{
if (this.listBox1.InvokeRequired)
{
AddTextCallback d = new AddTextCallback(AddText);
this.Invoke(d, new object[] { text });
}
else
{
this.listBox1.Items.Add(text);
}
}
I'm also have the same problem like you on last month but i solve that using this Receive multiple different messages TcpListener C# from stackoverflow. This helps me lot hope it helps to solve your problem also.
I'm not 100% sure you understand TCP sockets so here goes.
When you use a TCP listener socket you first bind to a port so that clients have a fixed, known point to connect to. This reserves the port for your socket until you give it up by calling Close() on that socket.
Next you Listen in order to begin the process of accepting clients on the port you bound to. You can do both this and the first step in one but as you haven't I haven't here.
Next you call Accept(). This blocks (halts execution) until a client connects and then it returns a socket which is dedicated to communication with that client. If you want to allow another client to connect, you have to call Accept() again.
You can then communicate with your client using the socket that was returned by Accept() until you're done, at which point you call Close() on that socket.
When you're done listening for new connections you call Close() on your listener socket.
However when you press your listen button the following happens:
You bind correctly, you begin listening correctly and then your call to ReceiveData() blocks on the Accept call until a client is received. You then receive some data (though this is TCP so that might not be the whole data!) and then you instantly close the connection to your client.
I presume to get the error you're getting you must then press listen again on your server. This therefore restarts the whole listener socket and when you get to bind to the port the second time your previous listener is still bound to it and thus the call fails because something's already allocated on that port.
Solution wise you need to keep the socket returned from the Accept() call open until you're done with it. Have the client handle the close by calling the Shutdown() method on their socket or establish some convention for marking the end of communication.
You're also going to run into trouble when you try and have multiple users connected and so at some point you're either going to require threads or some asynchronous sockets but I feel that's out the scope of this question.
I suggest you do not use AxMSWinsockLib.. Have a look at socket example given here where it shows how to create a client socket and server socket - https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx AND this one - https://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx

C# TCP Client to automatically connect to server listening on specific port

I seem to be having a hard time figuring out how to get my client app to automatically connect to a server app running on a separate machine on my LAN.
Right now the only way I'm able to get the client to connect to the server is by manually specifying the server's IP address in code:
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = neIPEndPoint(IPAddress.Parse("Server IP address goes here"), 8888);
My server app uses a TCP Listener, so I figured my client could do something similar, to be able to find the server, but I can't figure out how to implement it in code.
Code from my server app for finding the client to connect to:
private TcpListener tcpListener;
private Thread listenThread;
private int connectedClients = 0;
private delegate void WriteMessageDelegate(string msg);
public Form1()
{
InitializeComponent();
Server();
}
private void Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 8888);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
I've tried using a TextBox that the user can manually enter their server's IP address into (since they wouldn't have access to the code), but I think an automatic connection would be much more user friendly, especially since I don't know how to permanently save the user's server IP address if they use the above method of setting the IP for the client to connect to.
So, my question is: What would be the best method for me to enable my client to automatically connect to a server running on my LAN?
Thanks,
Patrick
UPDATE
I tried implementing the code for a UDP broadcast, but I can't seem to get it working.
Here is what I've added to my client (Along with the client code I had in there before):
public partial class Console : Form
{
//FIND SERVER
private void FindServer()
{
var Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("SomeRequestData");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);
Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, 8888));
var ServerResponseData = Client.Receive(ref ServerEp);
var ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
Console.WriteLine("Recived {0} from {1}", ServerResponse, ServerEp.Address.ToString());
Client.Close();
}
// SEND MESSAGES TO SERVER (VIA USER INTERACTION)
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("My IP Address was here (I tried changing it to "broadcast" as well"), 8888);
public Console()
{
InitializeComponent();
client.Connect(serverEndPoint);
}
private void SendMessage(string msg)
{
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(msg);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
Here is what I've added to my server code:
private void BroadcastToClients()
{
var Server = new UdpClient(8888);
var ResponseData = Encoding.ASCII.GetBytes("SomeResponseData");
while (true)
{
var ClientEp = new IPEndPoint(IPAddress.Any, 0);
var ClientRequestData = Server.Receive(ref ClientEp);
var ClientRequest = Encoding.ASCII.GetString(ClientRequestData);
Console.WriteLine("Recived {0} from {1}, sending response", ClientRequest, ClientEp.Address.ToString());
Server.Send(ResponseData, ResponseData.Length, ClientEp);
}
}
I'd imagine there must be some conflicting code in there, but since I'm so new to this, I can't seem to figure it out...
UPDATE
I've still not managed to make any progress on this. Anyone out there that might be able to chime in and help me figure out why this isn't working for me?
Your client app can send a broadcast on the local subnet, on startup, 'asking for server'.
Your server will be listening for that message, and replies to the client.
Now the client knows the server's IP address and can start the TCP connection.
You have it here: C# How to do Network discovery using UDP Broadcast

SocketException An existing connection was forcibly closed by the remote host

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.

invalid argument supplied on c# udp socket

I've been trying to make a simple udp chat application in c#. it was working an hour ago, but I don't exactly realize what happened to it or what exactly I've changed in it. when I try to listen for any incoming messages, I just get an exception saying "Invalid argument was supplied", pointing to the variable 'rcv'. Here's the code:
public partial class Form1 : Form
{
Socket sock = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"),
1234);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ThreadStart(send));
thread1.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Thread thread2 = new Thread(new ThreadStart(receive));
thread2.Start();
}
private void receive()
{
while (true)
{
byte[] rcv = new byte[2048];
int size = sock.Receive(rcv); // this is where the exception is, pointing at rcv.
char[] chars = new char[size];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int length = d.GetChars(rcv, 0, size, chars, 0);
System.String recv = new System.String(chars);
textBox1.Text += recv.ToString();
}
}
private void send()
{
byte[] msg = Encoding.UTF8.GetBytes(textBox1.Text);
sock.SendTo(msg, localEndPoint);
}
private void button3_Click(object sender, EventArgs e)
{
sock.Close();
}
}
I've honestly never seen this exception while working with sockets. I thought maybe the socket was open and in use so I tried closing it but with no success.
Any tips will be greatly appreciated.
From MSDN:
If you are using a connection-oriented protocol, you must either call Connect to establish a remote host connection, or Accept to accept an incoming connection prior to calling Receive. The Receive method will only read data that arrives from the remote host established in the Connect or Accept method. If you are using a connectionless protocol, you can also use the ReceiveFrom method. ReceiveFrom will allow you to receive data arriving from any host.
It appears you are not calling Connect, Accept, or ReceiveFrom in any case. Since a chat application follows (logically) a connection-oriented protocol, you should probably call Connect or Accept somewhere prior to Receive.

Categories