Good day all
This is a piece of code which is part of a small lan chat (expermentation) program, however when sending messages to this, the server, it is recieved (as per debugging I can see the results) but the gui fails to update (gui meaning richedit and label)
When I click send, the receiveText(string IP) is called, which executes and awaits for a connection, when it recieves a connetion, it handles as it should but,
Problem :
Only after this method (and related) have been executed, the gui updates, so when this method finishes, and its calling method finishes (button_click) too, only then while the program is waiting for input, they richedit displays the messages and the label is updated
I tried w/ and w/o the while loops, both have the same result
private void recieveText(string _IPADDRESS)
{
//initialise multicast group and bind to interface
Socket _listener_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, _PORT);
_listener_socket.Bind(ipep);
IPAddress localip = IPAddress.Parse("224.5.6.7");
_listener_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(localip, IPAddress.Any));
//recieve data to multicast group
//while (true)
//{
//while (_listener_socket.Connected)
//{
label1.Text = "listening...";
byte[] b = new byte[1024];
_listener_socket.Receive(b);
label1.Text = "message recieved";
redBox.AppendText("\n---------------------------------\n New Message :\n");
char[] chars = new char[b.Length / sizeof(char)];
System.Buffer.BlockCopy(b, 0, chars, 0, b.Length);
string t = new string(chars).Trim();
redBox.AppendText(t);
redBox.AppendText("\n----------------------------------\n\n");
//}
//}
}
In order to see updates and don't block the main thread you must receive the data in a separated thread.
Here is an example:
private void recieveText(string _IPADDRESS)
{
//initialise multicast group and bind to interface
Socket _listener_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, _PORT);
_listener_socket.Bind(ipep);
IPAddress localip = IPAddress.Parse("224.5.6.7");
_listener_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(localip, IPAddress.Any));
ThreadPool.QueueUserWorkItem((o) =>
{
BeginInvoke((Action)(() => { label1.Text = "listening..."; }));
while (_listener_socket.Connected)
{
byte[] b = new byte[1024];
_listener_socket.Receive(b);
char[] chars = new char[b.Length / sizeof(char)];
System.Buffer.BlockCopy(b, 0, chars, 0, b.Length);
string t = new string(chars).Trim();
BeginInvoke((Action)(() =>
{
label1.Text = "message recieved";
redBox.AppendText("\n---------------------------------\n New Message :\n");
redBox.AppendText(t);
redBox.AppendText("\n----------------------------------\n\n");
}));
}
});
}
This is the example using different threads as you requested BUT this is not the best way to do it, as I said in my comment the right way is to use the asynchronous methods, the old ones (BeginXXX/EndXXX) or the new async ones (XXXAsync).
Related
I am trying to discover a Belkin Wemo switch using C#. I am sending SSDP over the network to get back a response from the switch.
The following snippet creates a socket, sends SSDP and waits for 2 seconds to receive an answer. If nothing is read, it starts all again.
bool repeat = true;
while (repeat)
{
UdpClient udpClient = null;
try
{
// Creates the socket.
udpClient = new UdpClient(10140);
udpClient.Client.ReceiveTimeout = 2000;
IPAddress broadcastIpAddress = IPAddress.Parse("239.255.255.250");
IPEndPoint broadcastIpEndPoint = new IPEndPoint(broadcastIpAddress, 1900);
udpClient.JoinMulticastGroup(broadcastIpAddress);
// Sends SSDP.
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("M-SEARCH * HTTP/1.1\r\n");
stringBuilder.Append("ST: urn:Belkin:service:basicevent:1\r\n");
stringBuilder.Append("MX: 1\r\n");
stringBuilder.Append("MAN: \"ssdp:discover\"\r\n");
stringBuilder.Append("HOST: 239.255.255.250:1900\r\n");
stringBuilder.Append("\r\n");
byte[] bytesToSend = Encoding.UTF8.GetBytes(stringBuilder.ToString());
udpClient.Send(bytesToSend, bytesToSend.Length, broadcastIpEndPoint);
// Receives response.
IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] receivedBytes = udpClient.Receive(ref remoteIpEndPoint);
string receivedString = Encoding.UTF8.GetString(receivedBytes);
Console.WriteLine(receivedString);
repeat = false;
}
catch (SocketException) { }
finally
{
udpClient.Close();
}
}
Most of the time, a response is returned by the switch. However, sometimes it loops indefinitely without getting any feedback.
I am using Wireshark. In the second case, it happens that no SSDP is sent. I have no explanation about that. My system is Windows 7, maybe it helps...
In my adaption of a few multicast tutorials, I changed my method of sending packets.
In my case, I create a queue of packets of size bytes[1024], after which it is sent via Socket.Send() over all online network adapters
Problem:
When sending, another method called receiveMessage() is running on a separate thread. Using Socket.Bind(), it captures packets, but only 1 packet is captured.
Am I doing too much processing thus delaying (and losing) the packets received?
UPDATE
I am considering adding a queue for incoming packets, thus 1 threads captures and stores, the second processes the packets.
SendMethod
Socket _listener_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
foreach (IPAddress localIP in Dns.GetHostAddresses(Dns.GetHostName()).Where(i => i.AddressFamily == AddressFamily.InterNetwork))
{
//handle image and files
_listener_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(_MultiIP, localIP));
_listener_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 1);
_listener_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_listener_socket.MulticastLoopback = true;
_listener_socket.Connect(new IPEndPoint(_MultiIP, _PORT));
int count = MSGS_TO_SEND.Count;
while (count > 0)
{
count--;
byte[] temp = (byte[])(MSGS_TO_SEND.Dequeue());
_listener_socket.Send(temp, _BYTE_BUFFER_SIZE, SocketFlags.None);
MSGS_TO_SEND.Enqueue(temp);
}
//----------------------------------------------
//-------------------SEND DATA------------------
//----------------------------------------------
}
_listener_socket.Close();
Receive method
//initialise multicast group and bind to interface
Socket _sender_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, _PORT);
_sender_socket.Bind(ipep);
IPAddress localip = _MultiIP;
_sender_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(localip, IPAddress.Any));
//{
while (_sender_socket.IsBound && !bStop)
{
byte[] b = new byte[_BYTE_BUFFER_SIZE];
_sender_socket.Receive(b);
char[] chars = new char[_BYTE_BUFFER_SIZE];
System.Buffer.BlockCopy(b, 0, chars, 0, b.Length);
string _message = new string(chars).Trim();
string ip = _message.Substring(0, _message.IndexOf("~"));
_message = _message.Remove(0, _message.IndexOf("~") + 1);
string _flag = _message.Substring(0, _message.IndexOf("~"));
_message = _message.Remove(0, _message.IndexOf("~") + 1);
_message = _message.Replace("\0", string.Empty);
ip = "1.0";
icount++;
handleData(ip, _flag, _message);
}
If you wan't to try, here is a fully working example: https://github.com/efaruk/playground/tree/master/Multicasting
You can use those re-usable components (MulticastSender, MulticastReceiver,) in your project if you whish...
The sender doesn't have to bind or add membership. Any datagram socket can send to a multicast address. The receiver needs to add membership to the multicast address. The sender and receiver also need to agree upon the port (receiver should be bound to the port.)
Your Multicast Options in each example have the arguments reversed.
The sockets already have buffering from the kernel, so you don't need to complicate your code with message queues.
I have a program that multiple clients would be able to connect to a server using a socket:
private void performConnect()
{
while (true)
{
if (myList.Pending())
{
thrd = thrd + 1;
tcpClient = myList.AcceptTcpClient();
IPEndPoint ipEndPoint = (IPEndPoint)tcpClient.Client.RemoteEndPoint;
string clientIP = ipEndPoint.Address.ToString();
nStream[thrd] = tcpClient.GetStream();
currentMsg = "\n New IP client found :" + clientIP;
recieve[thrd].Start();
this.Invoke(new rcvData(addNotification));
try
{
addToIPList(clientIP);
}
catch (InvalidOperationException exp)
{
Console.Error.WriteLine(exp.Message);
}
Thread.Sleep(1000);
}
}
}
then the server could send data (chat messages) to a chosen client, using this code.
private void sendData(String data)
{
IPAddress ipep =IPAddress.Parse(comboBox1.SelectedItem.ToString());
Socket server = new Socket(AddressFamily.InterNetwork , SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipept = new IPEndPoint( ipep, hostPort);
NetworkStream nStream = tcpClient.GetStream();
ASCIIEncoding asciidata = new ASCIIEncoding();
byte[] buffer = asciidata.GetBytes(data);
if (nStream.CanWrite)
{
nStream.Write(buffer, 0, buffer.Length);
nStream.Flush();
}
}
the problem is that whatever IP i choose from the combo box, the message i send would always be directed/sent to the last IP that connected to the server.. Please somebody pinpoint my error! all help would be appreciated.
Look at those lines:
IPAddress ipep =IPAddress.Parse(comboBox1.SelectedItem.ToString());
Socket server = new Socket(AddressFamily.InterNetwork , SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipept = new IPEndPoint( ipep, hostPort);
NetworkStream nStream = tcpClient.GetStream();
You are creating a new socket but you are sending the data to the socket stored in the variable tcpClient that is global (since it was not defined in the method), thus totally ignoring the IPEndPoint parsed from the combobox.
You should not create a new socket in order to send data to the clients. Instead, store all clients in a collection and retrieve the appropriate one based on the input of the combobox.
I have UDP client chat, which sends messages to the server and get the responses back. I have two threads, one for sending, one for receiving messages. I get the exception with ReceiveFrom() method: "You must call the Bind method before performing this operation". But this is a client, I don't want to bind anything. For example this client works fine:
byte[] data = new byte[30];
string input, stringData;
IPEndPoint servIPEP = new IPEndPoint(
IPAddress.Parse("127.0.0.1"), 9050);
EndPoint servEP = (EndPoint)servIPEP;
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
string welcome = "Hello, are you there?";
data = Encoding.ASCII.GetBytes(welcome);
client.SendTo(data, data.Length, SocketFlags.None, servEP);
data = new byte[30];
int recv = client.ReceiveFrom(data, ref servEP); //works fine!
There is no bind for receiving. But when I create two threads error is thrown:
public ChatClient()
{
clientSock = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
servIPEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 32000);
servEP = (EndPoint)servIPEP;
}
public void ReceiveThread()
{
Thread receiveThread = new Thread(new ThreadStart(ReceiveData));
receiveThread.Start();
}
public void ReceiveData()
{
while(true){
clientSock.ReceiveFrom(buf, ref servEP); //Here I get ERROR
string msg = Encoding.ASCII.GetString(buf).Trim();
Console.WriteLine("New message: {0}",msg);
}
}
public void SendThread()
{
Thread sendThread = new Thread(new ThreadStart(SendData));
sendThread.Start();
}
public void SendData()
{
while (true)
{
Console.WriteLine("Enter message to send: ");
string msg = Console.ReadLine();
buf = Encoding.UTF8.GetBytes(msg);
clientSock.SendTo(buf, servEP);
}
}
}
static void Main(string[] args)
{
ChatClient client = new ChatClient();
client.SendThread();
client.ReceiveThread();
}
}
Thank you for your time.
Clearly SendTo() does an implicit bind, and ReceiveFrom() doesn't.
It doesn't make much sense to start receiving without a prior bind to at least set the port number you're receiving via. Otherwise how would you expect to get any data?
bellow is my code for server, which runs successfully but small problem is, when i send data from client from twice it accepts once.
e.g. if i run this server and client also togethor; first time it accepts data from client, second time when again i ping from client side it does not accept data third time when i ping from client side it accepts data, fourth time when i ping from client it does not accept data, fifth time when i ping from client it accepts data, and so on.....
thanking you in advanced.
class Program
{
//static byte[] Buffer { get; set; }
//static Socket sck;
static void Main(string[] args)
{
while (true)
{
Socket sck;
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sck.Bind(new IPEndPoint(0, 2000));
sck.Listen(10);
Socket accepted = sck.Accept();
byte [] Buffer = new byte[accepted.SendBufferSize];
int bytesRead = accepted.Receive(Buffer);
byte[] formatted = new byte[30];
for (int i = 0; i < 30; i++)
{
formatted[i] = Buffer[i];
}
string strData = Encoding.ASCII.GetString(formatted);
Console.Write(strData + "\r\n");
sck.Close();
accepted.Close();
}
}
}
This is not how you normally code a server. Usually, the listener stays up and just accepts new connections and closes them when done. It's possible that on the second attempt the client connects to your old listener just before you close it. Try keeping the listener open or else close the listener as soon as you accept a connection.
You need a TcpListner
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener(v=vs.71).aspx
Also, to handle many requests you need the server the process multiple requests on different threads. You'll need a thread pool. Look at ThreadPool.QueueUserWorkitem.
Here's a more complete C# TCP server example using that:
http://www.codeproject.com/KB/IP/dotnettcp.aspx
You need run the server into Thread
public void StartListener()
{
while (true)
{
mySocket = myListener.AcceptSocket();
Console.WriteLine("\r\nsocket type = {0}", mySocket.SocketType);
if (mySocket.Connected)
{
byte[] receive = new byte[1024];
mySocket.Receive(receive, 1024, 0);
string sBuffer = Encoding.ASCII.GetString(receive);
}
}
}
Then:
IPAddress IPaddress = Dns.Resolve(Dns.GetHostName()).AddressList[0];
TcpListener myListener = new TcpListener(IPaddress, 50);
myListener.Start();
Thread th = new Thread(new ThreadStart(StartListener));
th.Start();
More info:
TcpListener Class
Thread