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.
Related
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:
So I'm very interested in learning more sophisticated programming techniques and languages, and I've decided to further my study into C# by learning sockets and server programming. I stumbled upon a video that i bet a lot of you have already seen or heard of, and it's, in my opinion, pretty good at explaining most of what's going on.
So my problem is specifically with essentially taking this code and making it a chat system that takes info from a client, sends it to the server, then from the server to ALL clients. I've looked up any tutorials and other stack overflow pages to no avail, at least to me. I can't seem to figure it out, and when someone has an answer they've simply written "Found a solution" and more or less left it at that.
I am aware of this thread on SO, and I've tried what's been posted in there to no avail. I've also done my fair share of searching through google and whatnot, and with being new to sockets and all that, it's definitely not the easiest thing.
The Actual Problem
Here's my code for the server:
using static AppNameHere.ChatCommands;
namespace AppNameHere
{
public partial class Host : Form
{
public static Host host = null;
private static string response;
private static byte[] _buffer = new byte[1024];
private static List<Socket> _ClientSk = new List<Socket>();
private static Socket _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public Host()
{
InitializeComponent();
}
private void Host_Load(object sender, EventArgs e)
{
SetupServer();
}
private static void SetupServer()
{
_Socket.Bind(new IPEndPoint(IPAddress.Any, HostJoinSelect.portSelected));
_Socket.Listen(HostJoinSelect.playerTotal + 2);
_Socket.BeginAccept(new AsyncCallback(AccCallback), null);
}
private static void AccCallback(IAsyncResult iar)
{
Socket s = _Socket.EndAccept(iar);
_ClientSk.Add(s);
Console.WriteLine("Client Connected.");
s.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(RecCallback), s);
_Socket.BeginAccept(new AsyncCallback(AccCallback), null);
}
private static void RecCallback(IAsyncResult iar)
{
Socket s = (Socket)iar.AsyncState;
int received = s.EndReceive(iar);
byte[] dataBuf = new byte[received];
Buffer.BlockCopy(_buffer, 0, dataBuf, 0, received);
string t = Encoding.ASCII.GetString(dataBuf);
foreach (Socket socket in _ClientSk)
{
response = ChatCommandParser(t);
byte[] data = Encoding.ASCII.GetBytes(response);
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(RecCallback), socket);
}
}
private static void SendCallback(IAsyncResult iar)
{
Socket s = (Socket)iar.AsyncState;
s.EndSend(iar);
}
}
}
The using at the top is just a class I made for converting text to something else, so it's no obstruction. What really rustles my jimmies is the foreach loop that's, in theory, supposed to make it work, and it makes sense as it should be going through all the clients and sending them all messages, but if a client sends a message, nothing happens on the other clients. Only the original client gets the message back.
So both debugging and troubleshooting have shown that it runs through BeginSend and such, but it still only sends a message to that same client that i typed into which is just weird.
Thanks in advance, and please, if you have an answer then explain it to me cause I'm still learning, so a fix and an explanation would be nice.
P.S. Yes I know I'm using TCP and not UDP.
EDIT: The code I used for my client is in this pastebin link: https://pastebin.com/4WicEu2x
EDIT 2: I have a feeling the main issue is that in my client code, I have the client listening for messages only AFTER it sends a message. If this is it, then i'm dumber than a rock and would like to thank anyone who posted here telling me how to improve my program.
EDIT 3: What I wrote in my second edit was correct. If you're having an issue and you've followed the same guide I did in that youtube video, then just know that you should have Asynchronous Receiving in your client-side program as well as your server. I didn't think too much of the client side, but always check your code! Here's my edited client-side code (yes i know it needs LOTS of work):
namespace AppNameHere
{
public partial class Join : Form
{
public static Join join = null;
private static Socket _ClientSk = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static byte[] recBuf = new byte[1024];
public Join()
{
InitializeComponent();
}
private void Join_Load(object sender, EventArgs e)
{
}
private void Join_FormClosed(object sender, FormClosedEventArgs e)
{
if (HostJoinSelect.hjs != null)
{
HostJoinSelect.hjs.Show();
}
else
{
HostJoinSelect.hjs = new HostJoinSelect();
HostJoinSelect.hjs.Show();
}
}
private void Join_Shown(object sender, EventArgs e)
{
LoopConnect();
}
private static void Send()
{
string req = join.textBox1.Text;
byte[] buffer = Encoding.ASCII.GetBytes(req);
_ClientSk.Send(buffer);
}
private static void ConnectedCallback()
{
_ClientSk.BeginReceive(recBuf, 0, recBuf.Length, SocketFlags.None, new AsyncCallback(ReceivedCallback), _ClientSk);
}
private static void ReceivedCallback(IAsyncResult iar)
{
Socket s = (Socket)iar.AsyncState;
int rec = s.EndReceive(iar);
byte[] dataBuf = new byte[rec];
Buffer.BlockCopy(recBuf, 0, dataBuf, 0, rec);
string q = Encoding.ASCII.GetString(dataBuf);
join.Invoke(new MethodInvoker(delegate () {
join.listBox1.Items.Add(Form1.namesave + ": " + q);
join.listBox1.TopIndex = join.listBox1.Items.Count - 1;
}));
s.BeginReceive(recBuf, 0, recBuf.Length, SocketFlags.None, new AsyncCallback(ReceivedCallback), s);
}
private static void LoopConnect()
{
int attempts = 0;
while (!_ClientSk.Connected)
{
if (attempts < 4)
{
try
{
attempts++;
if (attempts <= 4)
{
_ClientSk.Connect(HostJoinSelect.IPSelectedJoin, HostJoinSelect.portSelectedJoin);
Console.WriteLine("Connected");
ConnectedCallback();
}
else
{
attempts = 0;
break;
}
}
catch (SocketException s)
{
if (attempts <= 4)
{
Console.WriteLine(s.Message + " | Connection attempts: " + attempts.ToString());
}
else
{
attempts = 0;
break;
}
}
}
else
{
MessageBox.Show("You failed to connect to " + HostJoinSelect.IPSelectedJoin + ":" + HostJoinSelect.portSelectedJoin + ", please ensure you have a means of connecting to this address.");
join.Close();
break;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
Send();
}
}
}
I changed the code from accepting messages only after it sent one itself to having an asynchronous BeginReceive to take in data sent by the server. Always review your code and logic!
Besides the fact that your code requires some fixes it still works. I executed it in my test project and it worked as you want (almost, short of concurrency issues).
Required concurrency fixes:
As Emir Curtovic mentioned you shouldn't use a common buffer. Use local variable instead. If you want you can utilize the same buffers between connections using ThreadLocal or AsyncLocal class-level fields. It will be both thread-safe and reduce a heap fragmentation hazard.
You cannot just use List for sockets. It is not thread safe. There are at least two possible fixes: a) use a lock {} around the _ClientSk.Add(s) call or b) use concurrent collections.
If your client connections come simultaneously the last bug may cause the behavior that you described. However, there is also a possibility that your client code has some issues as well. If after introducing the fixes you still experience the issue please post your client code as well.
In general, there is more work to be done with your code. For example you should handle client disconnections. Currently it will just throw exceptions on int received = s.EndReceive(iar) call any time your client decides to close the connection. Besides handling the exception you will need to add to your protocol some way to perform a graceful connection closing. For example, by handling EOF symbol. Here you will find a nice code sample from MSFT.
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
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.
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.