i'm trying to make an application which allows the connection between 2 PCs(i planned on making it multi threaded later but lets keep it more simple at the beginning). This could be either used for chatting or sending data to the other pc and he does something to the data and sends it back.
This is my coding so far:
Server:
class Program
{
private static StreamWriter serverStreamWriter;
private static StreamReader serverStreamReader;
private static bool StartServer()
{
//setting up Listener
TcpListener tcpServerListener = new TcpListener(IPAddress.Any, 56765);
tcpServerListener.Start();
Console.WriteLine("Server Started!");
Console.WriteLine("Waiting for Connection...");
Socket serverSocket = tcpServerListener.AcceptSocket();
try
{
if (serverSocket.Connected)
{
Console.WriteLine("Client connected to Server!");
//open network stream on accepted socket
NetworkStream serverSockStream = new NetworkStream(serverSocket);
serverStreamWriter = new StreamWriter(serverSockStream);
serverStreamReader = new StreamReader(serverSockStream);
}
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
return false;
}
return true;
}
static bool once = false;
static void Main(string[] args)
{
//Set Console Window Stuff
Console.Title = "Server";
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Green;
Console.BufferWidth = 120;
Console.Clear();
//Start Server
if (!StartServer())
Console.WriteLine("Error while Starting Server!");
//Waiting till Client sends Something
while (true)
{
string data = "Append Something to Me - ";
if (!once)//that check -.-
{
serverStreamWriter.WriteLine(data);
serverStreamWriter.Flush();
once = true;
}
Console.WriteLine("Client: " + serverStreamReader.ReadLine());
if (serverStreamReader.ReadLine() != data)
{
serverStreamWriter.WriteLine(data);
serverStreamWriter.Flush();
}
}
}
}
Client:
class Program
{
private static StreamReader clientStreamReader;
private static StreamWriter clientStreamWriter;
private static bool ConnectToServer()
{
try
{
TcpClient tcpClient = new TcpClient("127.0.0.1", 56765);
Console.WriteLine("Connected to Server!");
NetworkStream clientSockStream = tcpClient.GetStream();
clientStreamReader = new StreamReader(clientSockStream);
clientStreamWriter = new StreamWriter(clientSockStream);
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
return false;
}
return true;
}
private static void SendToServer(string message)
{
try
{
clientStreamWriter.WriteLine(message);
clientStreamWriter.Flush();
}
catch (Exception se)
{
Console.WriteLine(se.StackTrace);
}
}
static void Main(string[] args)
{
//Set Console Window Stuff
Console.Title = "Client";
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Red;
Console.BufferWidth = 120;
Console.Clear();
if (!ConnectToServer())
Console.WriteLine("Error while Connecting to Server!");
SendToServer("Send Me Data...");
//Waiting till Server sends Something
while (true)
{
string response = clientStreamReader.ReadLine();
Console.WriteLine(response + "|| Appending Text...");
response += "Appended Text!";
Console.WriteLine("Sended " + response + " back to server!");
SendToServer(response);
}
}
}
Even though this isn't really good coding, it works for me, BUT the main problem with this is it only works on my local machine. How would i make it so if i run the server app on my pc and my friend runs the client app on his pc those two connect!? Help would be really great since i wasn't able to found a detailed tutorial or such and i only created this Account to ask for help here :)
TcpClient tcpClient = new TcpClient("localhost", 3333);
Instead of "localhost", use the remote machine's address here.
Edit:
You don't seem to understand how this connection process works, so I'll try to explain it a little better.
Your server is opening up a socket on port 3333, listening for any connections. This process does not need any external IP adress.
You clients are trying to connect to the server. They need to know what server they're connecting to, so you need to supply them with an IP address. An example would be something like
TcpClient tcpClient = new TcpClient("127.0.0.1", 3333);
//this is identical to using "localhost"
There's no way for you to get around at some point using a remote address in the connection protocol. You can't just tell the client "connect on port 3333" and expect it to know exactly where it needs to connect.
The comment explaining how to resolve a local IP address isn't useful in your case, because what you ended up doing was just telling the client to connect to itself, as you resolved the client's IP address and tried to connect to that.
However, you can have multiple clients connect to the same server. In this case you won't need multiple remote IP addresses, you just tell all the clients to connect to the same remote address and then handle that on the server. This is where the RemoteEndPoint comes into effect.
At the server level you can use the RemoteEndPoint to find the IP address of the clients connecting to it, and use this IP address to return information to those clients.
All in all, you WILL have to use some hardcoded address for your initial
TcpClient tcpClient = new TcpClient(address, 3333);
step. There's no way around this.
Related
I created a project in c# to simulate a tcp client in c# using visual studio 2017 to understand how TCP/IP communications work at a very high level.
The problem is that the code bellow is throwing an exception "No connection could be made because the target computer actually refused 127.0.0.1:1080"
namespace SimpleTcpEchoClient
{
public class Program
{
static void Main(string[] args)
{
TcpClient ourTcpClient = null;
NetworkStream networkStream = null;
try
{
//initiate a TCP client connection to local loopback address at port 1080
ourTcpClient = new TcpClient();
ourTcpClient.Connect(new IPEndPoint(IPAddress.Loopback, 1080)); //HERE IS WHERE THE EXCEPTION IS THROWN
Console.WriteLine("Connected to server....");
//get the IO stream on this connection to write to
networkStream = ourTcpClient.GetStream();
//use UTF-8 and either 8-bit encoding due to MLLP-related recommendations
var messageToTransmit = "Hello from Client";
var byteBuffer = Encoding.UTF8.GetBytes(messageToTransmit);
//send a message through this connection using the IO stream
networkStream.Write(byteBuffer, 0, byteBuffer.Length);
Console.WriteLine("Data was sent data to server successfully....");
var bytesReceivedFromServer = networkStream.Read(byteBuffer, 0, byteBuffer.Length);
// Our server for this example has been designed to echo back the message
// keep reading from this stream until the message is echoed back
while (bytesReceivedFromServer < byteBuffer.Length)
{
bytesReceivedFromServer = networkStream.Read(byteBuffer, 0, byteBuffer.Length);
if (bytesReceivedFromServer == 0)
{
//exit the reading loop since there is no more data
break;
}
}
var receivedMessage = Encoding.UTF8.GetString(byteBuffer);
Console.WriteLine("Received message from server: {0}", receivedMessage);
Console.WriteLine("Press any key to exit program...");
Console.ReadLine();
}
catch (Exception ex)
{
//display any exceptions that occur to console
Console.WriteLine(ex.Message);
}
finally
{
//close the IO strem and the TCP connection
networkStream?.Close();
ourTcpClient?.Close();
}
}
}
}
I already tried to change the port but without success!
Can someone please help me?
It is solved now, my server was running on port 1081 instead of 1080 :)
The C#-Application is the TCP-Server and Delphi-Application represents the TCP-Client polling Server for information.
I'm using Microsoft Visual Studio Community 2017 and .NET-Framework 4.5.1 for the C#-Application and Delphi 7 (Embarcadero) for the Client-Application.
Both Applications run on the same PC, therefore I set IP-Address to "localhost" or "127.0.0.1".
The Port is 12345.
class Program
{
static void Main(string[] args)
{
int port = 0;
IPHostEntry host;
IPAddress localAddress;
try
{
port = 12345;
host = Dns.GetHostEntry("localhost");
localAddress = host.AddressList[0];
Console.WriteLine("Server waits for a client");
// init Listener
TcpListener listener = new TcpListener(localAddress, port);
// start Listener
listener.Start();
// Wait for a client..
TcpClient c = listener.AcceptTcpClient();
Console.WriteLine("Connection established.");
//..
// Close connection
c.Close();
// stop Listener
listener.Stop();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
}
My Problem is, that I get error # 10061 "Connection refused" in the Client (Delphi) Application when the socket tries to connect to the server.
TForm1 = class(TForm)
TcpClient1: TTcpClient;
btnConnect: TButton;
// ..
procedure TForm1.btnConnectClick(Sender: TObject);
begin
// try to connect to TCP-Server
TcpClient1.RemoteHost := 'localhost';
TcpClient1.RemotePort := '12345';
if not TcpClient1.Connect() then // Error 10061
begin
ShowMessage('No connection to server');
end
else
begin
ShowMessage('Connected with server.');
end;
end;
In Delphi I tried the component TcpClient as well as the Indy component TIdTCPClient - the error appears on both.
For testing purpose I wrote a Client-Application in C# where the error didn't occur (same address and port).
class Program
{
static void Main(string[] args)
{
try
{
// init Client
TcpClient c = new TcpClient("localhost", 12345);
Console.WriteLine("Connected to localhost.");
// ..
// close connection
Console.WriteLine("Close connection.");
c.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
Console.WriteLine("Press Enter to exit... ");
string cmd = Console.ReadLine();
}
}
My guess is, that there is something between C# and Delphi, but I have no idea what.
Did anyone has an idea why I cannot establish a connection with the Delphi-Application?
Update: It seems to work, when the C#-Server accepts Clients from any IP-Address.
// ..
// host = Dns.GetHostEntry("localhost");
// localAddress = host.AddressList[0];
Console.WriteLine("Server waits for a client");
// init Listener
TcpListener listener = new TcpListener(IPAddress.Any, port);
//..
In C# localAddress can be of Address Family IPv4, IPv6 or others, I wasn't able to connect with my Delphi-Application that works with IPv4.
My current solution:
I loop through the AddressList and make sure that I get an IP-Address of IPv4-Family.
host = Dns.GetHostEntry("localhost");
for (int i = 0; i <= host.AddressList.Length - 1; i++)
{
if (host.AddressList[i].AddressFamily == AddressFamily.InterNetwork) // check if family is IPv4
{
localAddress = host.AddressList[i];
// init Listener
listener = new TcpListener(localAddress, port);
// start Listener
listener.Start();
// ..
}
}
I saw on the internet how to create a socket server in C#,
after sending to the server one message the server closes.
I have been wondering what can I do to change it so it can handle multiple messages.
The code:
static void startServer() {
Console.WriteLine("[*] Opening server...");
TcpListener listener = new TcpListener(IPAddress.Any, 45784);
listener.Start();
Console.WriteLine("[*] Server waiting on port " + 45784);
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client connected!");
StreamReader STR = new StreamReader(client.GetStream());
Console.WriteLine(STR.ReadLine());
}
static void Main(string[] args)
{
string ip = GetIpAdress();
Console.WriteLine("server on: " + ip);
startServer();
Console.Read();
}
I believe this is pretty basic. Simply put your code read only one message and exit.
To read multiple message you just need to put a while loop around this line.
Console.WriteLine(STR.ReadLine());
Your server is stopping after receiving one message because that's all you've told it to do (so far).
These lines:
StreamReader STR = new StreamReader(client.GetStream());
Console.WriteLine(STR.ReadLine());
Will handle one message from the client, and then stop since you aren't telling it to grab another message.
If you want the server to listen and handle an arbitrary number of messages, you'll want to put this code in a loop.
Try this:
static TcpListener StartServer()
{
Console.WriteLine("[*] Opening server...");
TcpListener listener = new TcpListener(IPAddress.Any, 45784);
listener.Start();
Console.WriteLine("[*] Server waiting on port " + 45784);
return listener;
}
static void Listen(CancellationToken cancellationToken)
{
string ip = GetIpAddress();
Console.WriteLine("server on: ");
var listener = StartServer();
var client = listener.AcceptTcpClient();
Console.WriteLine("Client connected!");
var reader = new StreamReader(client.GetStream());
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine(reader.ReadLine());
}
}
static void Main(string[] args)
{
var cancellationSource = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cancellationSource.Cancel();
};
Listen(cancellationSource.Token);
}
This code will continue to get lines from the remote client until the server is canceled with Ctrl-C. It uses a CancellationToken to hook into the cancellation event, but you could also use a bool flag if you wanted.
Caveats: This only accepts messages from a single client, not multiple clients (that's a different challenge). Also, once the cancel event is sent, the server waits for one more message from the client before exiting and closing the connection, because ReadLine() blocks the thread until it sees a message come in.
I meant, multiple messages, one after the other from a single client.
You need to add some loops.
listener.Start();
while(true) { // beware: please avoid never-ending loop, and define a proper exit condition
TcpClient client = listener.AcceptTcpClient();
using(client) {
Console.WriteLine("Client connected!");
StreamReader STR = new StreamReader(client.GetStream());
string s = STR.ReadLine();
while(s != null) { // read until EOF
Console.WriteLine(s);
}
}
}
listener.Stop(); // this should always be called after exit condition occurs
I am trying to make 2 programs (in console application) in .NET that communicate together through the web (the code is from a video that you can find below, I am just trying to make the code work before adapting it). Forgive me, I'm not an experienced programmer.
I have a server and a client, they work perfectly when I run both of them on my computer (locally).
I can connect multiple clients to the server, send requests and get a response.
I am facing the problem when i run the server on a computer and the client on an other one and I try to connect through the internet.
I can connect to the server but communication does not work, there is no data exchange when try to request time as an example. I think that the problem is mostly coming from the network itself than the code.
Here's the code for the server:
class Program
{
private static Socket _serverSocket;
private static readonly List<Socket> _clientSockets = new List<Socket>();
private const int _BUFFER_SIZE = 2048;
private const int _PORT = 50114;
private static readonly byte[] _buffer = new byte[_BUFFER_SIZE];
static void Main()
{
Console.Title = "Server";
SetupServer();
Console.ReadLine(); // When we press enter close everything
CloseAllSockets();
}
private static void SetupServer()
{
// IPAddress addip = GetBroadcastAddress();
Console.WriteLine("Setting up server...");
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(new IPEndPoint(IPAddress.Any , _PORT));
_serverSocket.Listen(5);
_serverSocket.BeginAccept(AcceptCallback, null);
Console.WriteLine("Server setup complete");
}
/// <summary>
/// Close all connected client (we do not need to shutdown the server socket as its connections
/// are already closed with the clients)
/// </summary>
private static void CloseAllSockets()
{
foreach (Socket socket in _clientSockets)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
_serverSocket.Close();
}
private static void AcceptCallback(IAsyncResult AR)
{
Socket socket;
try
{
socket = _serverSocket.EndAccept(AR);
}
catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
{
return;
}
_clientSockets.Add(socket);
socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
Console.WriteLine("Client connected, waiting for request...");
_serverSocket.BeginAccept(AcceptCallback, null);
}
private static void ReceiveCallback(IAsyncResult AR)
{
Socket current = (Socket)AR.AsyncState;
int received;
try
{
received = current.EndReceive(AR);
}
catch (SocketException)
{
Console.WriteLine("Client forcefully disconnected");
current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
_clientSockets.Remove(current);
return;
}
byte[] recBuf = new byte[received];
Array.Copy(_buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);
Console.WriteLine("Received Text: " + text);
if (text.ToLower() == "get time") // Client requested time
{
Console.WriteLine("Text is a get time request");
byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
current.Send(data);
Console.WriteLine("Time sent to client");
}
else if (text.ToLower() == "exit") // Client wants to exit gracefully
{
// Always Shutdown before closing
current.Shutdown(SocketShutdown.Both);
current.Close();
_clientSockets.Remove(current);
Console.WriteLine("Client disconnected");
return;
}
else
{
Console.WriteLine("Text is an invalid request");
byte[] data = Encoding.ASCII.GetBytes("Invalid request");
current.Send(data);
Console.WriteLine("Warning Sent");
}
current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
}
}
And here the client code:
class Program
{
private static readonly Socket _clientSocket = new Socket
(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private const int _PORT = 50114;
static void Main()
{
Console.Title = "Client";
ConnectToServer();
RequestLoop();
Exit();
}
private static void ConnectToServer()
{
int attempts = 0;
while (!_clientSocket.Connected)
{
try
{
attempts++;
Console.WriteLine("Connection attempt " + attempts);
_clientSocket.Connect("IpAddr", _PORT);
}
catch (SocketException)
{
Console.Clear();
}
}
Console.Clear();
Console.WriteLine("Connected");
}
private static void RequestLoop()
{
Console.WriteLine(#"<Type ""exit"" to properly disconnect client>");
while (true)
{
SendRequest();
ReceiveResponse();
}
}
/// <summary>
/// Close socket and exit app
/// </summary>
private static void Exit()
{
SendString("exit"); // Tell the server we re exiting
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Close();
Environment.Exit(0);
}
private static void SendRequest()
{
Console.Write("Send a request: ");
string request = Console.ReadLine();
SendString(request);
if (request.ToLower() == "exit")
{
Exit();
}
}
/// <summary>
/// Sends a string to the server with ASCII encoding
/// </summary>
private static void SendString(string text)
{
byte[] buffer = Encoding.ASCII.GetBytes(text);
_clientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);
}
private static void ReceiveResponse()
{
var buffer = new byte[2048];
int received = _clientSocket.Receive(buffer, SocketFlags.None);
if (received == 0) return;
var data = new byte[received];
Array.Copy(buffer, data, received);
string text = Encoding.ASCII.GetString(data);
Console.WriteLine(text);
}
}
static void Main()
{
Console.Title = "Client";
ConnectToServer();
RequestLoop();
Exit();
}
private static void ConnectToServer()
{
int attempts = 0;
while (!_clientSocket.Connected)
{
try
{
attempts++;
Console.WriteLine("Connection attempt " + attempts);
_clientSocket.Connect("IpAddr", _PORT);
}
catch (SocketException)
{
Console.Clear();
}
}
Console.Clear();
Console.WriteLine("Connected");
}
"IpAddr" is a placeholder for the public IP of the router.
This is the video my current code is based on: https://www.youtube.com/watch?v=xgLRe7QV6QI
I took the code directly from it (you can find the 2 code files on the site linked in description).
I run the server, it awaits for a connection. I then run the clients which tries to connect to the server. I connects and on the server it shows the successful connection. The client then sends a request like "get time" and the server is supposed to catch it and respond:
byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
current.Send(data);
Back to network side:
Here is a list of all the things I have tried, that were the usual main causes of the problem after looking for a solution for about a full day:
I already have a static public IP for the router (so the public IP never changes). Even though, I created a dynamic dns on noip.com.
I gave a static lease to the computer the server runs on, so it has always the same local ip.
I created rules in the windows firewall to make sure the port I use is opened. I did this on both computers trying to communicate.
I forwarded the port on the router so it points to the local ip of the computer the server runs on. (I tried with a lot of different ports, no chance)
I tried activating the "DMZ" on the router but it's most likely not a solution
I tried to create a ASP.NET website which page returns a string, publish it with IIS 7.5 and set it up. Works on localhost but using the public ip like "xx.xxx.xxx.xx:PORT/default/index" I get an error. Yet it shows the website name in the error. Also, when using the local IP of the computer, it doesn't work either (something like 192.168.1.180).
Thanks for you help.
I learned about message framing, Thank you CodeCaster.
For people who are curious about it, here is an interesting link i found about it: http://blog.stephencleary.com/2009/04/message-framing.html
But before trying to change the code, I ran the server on an AWS vps and it worked instantly, the problem was probably comming from my isp or my router. I am just wondering how can it work without handling message framing.
I need a socket communication between my own written java server and C# client, the problem is that the C# client can't receive any messages from my java server, but sending messages to my java server works.
my workflow:
Java: Create Server
Java: Waiting for Client connection
c#: Create Client
c#: Build connection to the server
c#: send a msg to the server
Java: msg received
java: send msg to c# client
c#: receiving msg from server <- this is the point where the client waits for a message but never get.
Java Server code:
public class Communicator {
private int m_port;
private Socket m_socket;
private ServerSocket m_serverSocket;
public Communicator(int port) {
this.m_port = port;
initConnection();
}
private void initConnection() {
try {
System.out.println("Creating Server");
m_serverSocket = new ServerSocket(m_port);
System.out.println("Waiting for client connection");
m_socket = m_serverSocket.accept();
System.out.println("Connection made");
} catch (IOException e) {
e.printStackTrace();
}
}
public String sendMsg(JSONMessage msg) {
try {
//get msg
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(m_socket.getInputStream()));
System.out.println("Waiting for msg...");
String answer = bufferedReader.readLine();
System.out.println("Received: " + answer);
//send msg
PrintWriter writer = new PrintWriter(m_socket.getOutputStream(),true);
writer.print(msg.getMsg());
System.out.println("Sending: " + msg.getMsg());
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
My C# client code:
class Communicator
{
private int m_port;
private Thread mainThread;
public Communicator(int port)
{
m_port = port;
mainThread = new Thread(new ThreadStart(this.initConnection));
mainThread.Start();
}
public void initConnection()
{
IPEndPoint ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), m_port);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
Console.WriteLine("Trying to build connection");
server.Connect(ip);
Console.WriteLine("Connection successful");
NetworkStream ns = new NetworkStream(server);
StreamReader sr = new StreamReader(ns);
StreamWriter sw = new StreamWriter(ns);
string data;
string welcome = "Hello";
Console.WriteLine("Sending: " + welcome);
sw.WriteLine(welcome);
sw.Flush();
Console.WriteLine("Receiving...");
data = sr.ReadLine();
// --> NEVER REACHING THIS POINT <---
Console.WriteLine("Received: " + data);
}
catch (SocketException e)
{
Console.WriteLine("Connection failed.");
return;
}
}
}
Does somebody has any idea why it never reaches my client code Console.WriteLine("Received: " + data); ?
I already tried with waits on both sides. I'm not getting any exceptions or error so I don't have really an idea where my problem is.
Thanks
If your receiver is expecting lines, your sender has to send lines. Your sender does not send lines, so the receiver waits forever until it gets one.
To avoid these kinds of problems in the future, you should always make a specification document that explains how your protocol works, ideally at the byte level. It should specify whether the protocol contains messages and if so, how the sender marks message boundaries and how the receiver identifies them.
Here, your receiver identifies message boundaries by looking for line endings. But your sender doesn't mark message boundaries with line endings. So the receiver waits forever.
If you had a protocol specification, this would have been obvious. In the future, I strongly urge you to invest the time to specify every protocol you implement.
You need to use println() which adds a new line instead of print(). In Java, readLine waits for a new line and I would expect it to do the same in C#. Also println will auto-flush, so you don't need to flush as well.
If you intend to use this connection mreo than once, you need to keep the BufferedReader and PrintWriter for the connection. (So I suggest you create these after the socket is created/accepted) Creating these multiple times for the same socket can be error prone and confusing.