I need to use udp and tcp connections in my application,the TcpClient/TcpListener would rarely be active,but the udp one would be the main usage.
This is the server code:
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 25655);
listener.Start();
Socket sck = listener.AcceptTcpClient().Client;
UdpClient udpServer = new UdpClient(1100);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
var data = udpServer.Receive(ref remoteEP);
string result = Encoding.UTF8.GetString(data);
Console.WriteLine(result);
Console.Read();
}
And this is the Client:
static void Main(string[] args)
{
TcpClient client = new TcpClient("127.0.0.1", 25655);
Socket sck = client.Client;
UdpClient udpclient = new UdpClient();
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1100); // endpoint where server is listening
udpclient.Connect(ep);
byte[] data = UTF8Encoding.UTF8.GetBytes("Hello");
udpclient.Send(data,data.Length);
}
I'm establishing the Tcp connection at first,then i'm trying to connect and send data from the client to the server.
From a breakpoint i add, i can see that the Tcp part works properly,the client finishes the program but in the server,it's hangs on the receiving part var data = udpServer.Receive(ref remoteEP);
like no data arrived..when i remove the tcp code part(the first 2 lines from the server and the client) it works great,shows the result message.
Does anyone know why im unable to get the data from the client?
Thanks in advance.
The main difference between UDP and TCP is that TCP is going to try to resend the message until the server tells the client it has received it. UDP is going to send and forget it even if the packet never reach or the host doesn't exist at all
Here is the flow of your code
Server starts up TCP
Client sends TCP
Server Receives TCP
Client sends UDP (server did not listen yet, packet lost but UDP doesn't care)
Server starts to listen to UDP
Server waiting for UDP to come <--- hang
You would like to do some multithread programming and start both of them at the same time before you tries to send message from the client.
The thing is that listener.AcceptTcpClient() blocks your current thread and UdpClient on server side is not established before Tcp connection created. In fact, your server is waiting for Tcp connection and only after that starting listening of Udp connections, while your client creates 2 connections one by one. My suggestions is - your server starting listening Udp port after the moment client actually sent data. The easiest way to check my suggestions - for client code add Thread.Sleep(1000) before sending data via UDP. In order to make that working you probably need to modify your code not blocking main thread but separate Tcp and Udp in the way similar to this:
static void Main(string[] args)
{
Task.Factory.StartNew(() =>
{
TcpListener listener = new TcpListener(IPAddress.Any, 25655);
listener.Start();
Socket sck = listener.AcceptTcpClient().Client;
// ToDo: further actions related to TCP client
}, TaskCreationOptions.LongRunning);
UdpClient udpServer = new UdpClient(1100);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
var data = udpServer.Receive(ref remoteEP);
string result = Encoding.UTF8.GetString(data);
Console.WriteLine(result);
Console.Read();
}
client code can probably stay as it is for this example, but for real project I would recommend to separate that as well, as for sure you would like to get back some data from server via Tcp.
What if you first start the UDP client on server side and then establish the TCP connection between client and server?!
Server
static void Main(string[] args)
{
UdpClient udpServer = new UdpClient(1100);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
TcpListener listener = new TcpListener(IPAddress.Any, 25655);
listener.Start();
Socket sck = listener.AcceptTcpClient().Client;
var data = udpServer.Receive(ref remoteEP);
string result = Encoding.UTF8.GetString(data);
Console.WriteLine(result);
Console.Read();
}
Client
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 25655);
UdpClient udpclient = new UdpClient();
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1100); // endpoint where server is listening
udpclient.Connect(ep);
byte[] data = UTF8Encoding.UTF8.GetBytes("Hello");
udpclient.Send(data, data.Length);
}
Related
I am having trouble with my c# tcp code.
When I run the server and the client on the same computer, it will connect just fine.
But when I run the client on a different PC or on a phone, I get: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
Here is the server code:
private static void CreateServer()
{
TcpListener server = null;
try
{
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
Console.Write("Waiting for a connection... ");
/*
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
var ipAddress = ipHostInfo.AddressList;
Console.WriteLine(ipHostInfo.HostName);
Console.WriteLine(ipAddress[0]);
*/
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int i;
try
{
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
stream.Write(msg, 0, msg.Length);
}
}
catch(IOException e)
{
//Console.WriteLine(e);
Console.WriteLine("Restarting Server");
//client.Close();
//CreateServer();
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
//Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
I removed most of the comments. But that is the basic example for a tcp server from the documentation.
the client connect code is very simple:
tcpClient = new TcpClient();
tcpClient.Connect("192.168.0.7", 13000);
with the declaration for tcpClient saved in a less local spot for retaining and quickly reconnecting.
What I have tried:
I have made sure the IP address is correct, I even port forwarded and used my external IP, but got the same issue.
I made sure the firewall is not blocking the app on either device.
I tried using either device as the server.
I've looked up the problem and the only other person to have this issue needed to make sure he put in the correct IP and fix his firewall settings. I'm probably missing something super obvious.
One final piece of information, one device is wired to the router, I don't know if that is messing with anything.
One other thing, I tried:
tcpClient.Connect(new IPEndPoint(IPAddress.Parse("192.168.0.7"), 13000));
as well.
Whelp I was right. It was something very obvious and honestly dumb on my part.
on the server side:
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
does not result in the server listening on its ipv4, instead it listens on an ipv6
so what you want:
Remove the localAddr declaration, as it is not important, and instead of calling:
server = new TcpListener(localAddr, port);
call:
server = new TcpListener(IPAddress.Any, port);
IPAddress.Any is used to listen across all of the network interfaces the device has.
I'm trying to connect to a C# TCP server I'm running on EC2.
But my server's not responding. This is the code that running on the EC2:
static void Main(string[] args)
{
TcpListener serverSocket = new TcpListener(8888);
TcpClient clientSocket = default(TcpClient);
serverSocket.Start();
clientSocket = serverSocket.AcceptTcpClient();
Console.WriteLine("new client connected");
}
And them from my own PC I'm trying to run this code:
static void Main(string[] args)
{
TcpClient clientSocket = new TcpClient();
clientSocket.Connect("35.163.41.3", 8888);
Console.WriteLine("you connected to the server!");
}
This is the security group of my EC2:
What could the problem be?
It could be a number of things. First thing I would check is Windows Firewall on the server to make sure that it is allowing that port.
I'm trying to implement Hole punching using C# but unfortunately I spent hours to figure out why it doesn't work for me. Here is my problem:
I have a third part server that I can manage all external IPs for the peers on, and of course my router is behind a NAT, and I assume all my peers are also behind NATs.
Say if I managed to figure out all slaves (peers), End points (external ips). Where to put the external ip address of my server which runs on my pc (not the third party one), and where to put the peer ip address?
This is my code:
public void HolePunch(String ServerIp, Int32 Port) // if I put my external ip here I get Exception (An address incompatible with the requested protocol was used)
{
IPEndPoint LocalPt = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], Port);
UdpClient Client = new UdpClient();
Client.ExclusiveAddressUse = false;
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
Client.Client.Bind(LocalPt);
IPEndPoint RemotePt = new IPEndPoint(IPAddress.Parse(ServerIp), Port);
// This Part Sends your local endpoint to the server so if the two peers are on the same nat they can bypass it, you can omit this if you wish to just use the remote endpoint.
byte[] IPBuffer = System.Text.Encoding.UTF8.GetBytes(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString());
byte[] LengthBuffer = BitConverter.GetBytes(IPBuffer.Length);
byte[] PortBuffer = BitConverter.GetBytes(Port);
byte[] Buffer = new byte[IPBuffer.Length + LengthBuffer.Length + PortBuffer.Length];
LengthBuffer.CopyTo(Buffer,0);
IPBuffer.CopyTo(Buffer, LengthBuffer.Length);
PortBuffer.CopyTo(Buffer, IPBuffer.Length + LengthBuffer.Length);
Client.BeginSend(Buffer, Buffer.Length, RemotePt, new AsyncCallback(SendCallback), Client);
// Wait to receve something
BeginReceive(Client, Port);
// you may want to use a auto or manual ResetEvent here and have the server send back a confirmation, the server should have now stored your local (you sent it) and remote endpoint.
// you now need to work out who you need to connect to then ask the server for there remote and local end point then need to try to connect to the local first then the remote.
// if the server knows who you need to connect to you could just have it send you the endpoints as the confirmation.
// you may also need to keep this open with a keepalive packet untill it is time to connect to the peer or peers.
// once you have the endpoints of the peer you can close this connection unless you need to keep asking the server for other endpoints
Client.Close();
}
public void ConnectToPeer(String PeerIp, Int32 Port)
{
IPEndPoint LocalPt = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], Port);
UdpClient Client = new UdpClient();
Client.ExclusiveAddressUse = false;
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
Client.Client.Bind(LocalPt);
IPEndPoint RemotePt = new IPEndPoint(IPAddress.Parse(PeerIp), Port);
Client.Connect(RemotePt);
//you may want to keep the peer client connections in a list.
BeginReceive(Client, Port);
}
public void SendCallback(IAsyncResult ar)
{
UdpClient Client = (UdpClient)ar.AsyncState;
Client.EndSend(ar);
}
public void BeginReceive(UdpClient Client, Int32 Port)
{
IPEndPoint ListenPt = new IPEndPoint(IPAddress.Any, Port);
Object[] State = new Object[] { Client, ListenPt };
Client.BeginReceive(new AsyncCallback(ReceiveCallback), State);
}
public void ReceiveCallback(IAsyncResult ar)
{
UdpClient Client = (UdpClient)((Object[])ar.AsyncState)[0];
IPEndPoint ListenPt = (IPEndPoint)((Object[])ar.AsyncState)[0];
Byte[] receiveBytes = Client.EndReceive(ar, ref ListenPt);
}
EDIT :
the code works will if I give it my local ip and if my clients in my pc .. but if I supply it an external ip it doesn't work ( the exception in the first line comment )
I have a socket that serves a single request-response purpose.
I set it up on port XXX let it wait for a connection, read the data and reply with some data.
I would like to open a new socket on the same port. As soon as the response was sent.
That is handled externally (there is a manager that is checking the state of the thread and if it was used it disposes it and creates a new one.
The problem is that it gets blocked on
_socket = _socket.Accept();
and when a new client tries to connect it never leaves this line. (And client gets no reply).
The socket is running in
new Thread(Run);
and here is my Run method:
private void Run()
{
var ipHostInfo = Dns.Resolve(Dns.GetHostName());
var ipAddress = ipHostInfo.AddressList[0];
var localEndPoint = new IPEndPoint(ipAddress, Port);
_socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
try
{
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_socket.Bind(localEndPoint);
_socket.Listen(100);
_socket = _socket.Accept();
var data = string.Empty;
while (true)
{
var bytes = new byte[1024];
var bytesRec = _socket.Receive(bytes);
data += Encoding.UTF8.GetString(bytes, 0, bytesRec);
if (data.IndexOf("<EOF>", StringComparison.Ordinal) <= -1) continue;
var dataWithoutEof = data.Substring(0, data.IndexOf("<EOF>", StringComparison.Ordinal));
//TODO: do smt with the data
break;
}
var byteData = Encoding.UTF8.GetBytes("testResponse" + "<EOF>");
_socket.Send(byteData);
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
I suppose that I am not closing the existing socket correctly.
You code is wrong you should not expect this method to exit because you want your server up and running the whole time. I am assuming here you call run several times. Don't do that.
The code becomes then something like this :
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_socket.Bind(localEndPoint);
_socket.Listen(100);
while (true)
{
var _servicingsocket = _socket.Accept();
....
_servicingsocket.close();
}
accept is a blocking call. That waits for a new connection.
_socket is a listening socket and must be kept during the lifetime of the server.
A TCP connection is based on the notion of a socket pair.
When the server starts you have a single socket that listens on port 100.
Suppose a connection is established, then accept returns what is called a servicing socket that is basically a clone from the listening socket. This means that it is also using source port 100, but because it is a servicing socket it belongs to a socket pair that identifies the connection. A socket pair is the combination of 2 sockets, your own socket and the peer. When a data comes in, TCP will iterate through the socket pairs to find the right socket.
An additional advantage of doing it this way is that you allow other connection attempts to queue up on the listening socket while you are processing the first request. Your _socket is overwritten with the servicing socket and you are then assuming that the listening socket is going to be garbage collected. I am not sure if this is going to happen because I haven't tried it like you are doing it in your code because it is a bad idea in the first place because it implements idisposable. (https://msdn.microsoft.com/en-us/library/system.net.sockets.socket%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396) If you really want to close the server you have to make sure to close both the servicing socket and the listening socket to make the code clean.
I have some client-server socket code that I want to be able to construct and (re)connect to periodically the same endpoint address: localhost:17999
Here is the server:
// Listen for a connection:
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Loopback, 17999);
Socket listener = new Socket(IPAddress.Loopback.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
listener.Bind(localEndPoint);
listener.Listen(1);
// Accept the connection and send a message:
Socket handler = listener.Accept();
byte[] bytes = new byte[1024];
bytes = Encoding.ASCII.GetBytes("The Message...");
handler.Send(bytes);
// Clean up
handler.Shutdown(SocketShutdown.Both);
handler.Close();
handler.Dispose();
listener.Shutdown(SocketShutdown.Both);
listener.Close();
listener.Dispose();
And here is the client:
byte[] bytes = new byte[1024];
Socket receiver = new Socket(IPAddress.Loopback.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
receiver.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
receiver.Connect(new IPEndPoint(IPAddress.Loopback, 17999));
int num_bytes_received = receiver.Receive(bytes);
string result = Encoding.ASCII.GetString(bytes, 0, num_bytes_received);
receiver.Shutdown(SocketShutdown.Both);
receiver.Close();
receiver.Dispose();
When I create the client and server for the first time, it works fine. However when I create it again, I get an error:
"A request to send or receive data was disallowed because the socket is
not conne cted and (when sending on a datagram socket using a sendto
call) no address was supplied"
I would like to be able to spin up this mechanism arbitrarily whenever I need to with the following order of events:
Launch the server and wait to accept a connection
Launch the client and connect to the server
Accept the client connection at the server
Send a message to the client
Repeat when necessary
How can I do this?
Thx in Advance!
EDIT: Each time I build the client and server objects it is from a different process.
You have two issues:
1) You're closing the listener. Just leave it open.
2) You're setting ReuseAddress on the wrong socket and way too late. Set it on the listening socket before you call bind (since that's when you use the address).
Setting ReuseAddress on a socket you aren't going to bind doesn't do anything. You can remove that from the client.
I tried what Gene suggested and it seems to work:
// Listen for a connection:
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Loopback, 17999);
using (Socket listener = new Socket(IPAddress.Loopback.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
{
listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
listener.Bind(localEndPoint);
listener.Listen(1);
Thread t = new Thread(() =>
{
// Accept the connection and send a message:
using (Socket handler = listener.Accept())
{
byte[] bytes = new byte[1024];
bytes = Encoding.ASCII.GetBytes("The Message...");
handler.Send(bytes);
}
});
t.Start();
t.Join();
}
Thanks, all!