I'm trying to implement a small tcp based application in C#. I'm new to TCP programming.
The app is really simple. It's a client/server scenario, which support max 2 clients. One client will be an "external" IP, the other will be the host itself.
Everytime a client connect to the server, it begins to receive and send packets from/to the server.
I have set up a small console app which implements both TCP server side code and TCP client code.
The server use a listener binded to a specific port and wait for client connections. Once a client is connected, it spawn a new thread to handle communication with the client.
The client simply connect to the server and once the connection is estabilished it starts to receive and send pakcets.
As I said before "the host is also client of itself", but this leads to an issue. If the client send a packet to the server, both server and client claims to have received a packet. It is normal? Am I missing something?
UPDATE 2 (fixing issue)
I think I've found the issue. I need to "reset" the buffer once the send operation is done by the client
case SocketAsyncOperation.Send:
// Put in listen mode
// Buffer reset AFTER send and BEFORE receive
_receiver.SetBuffer(new byte[4096], 0, 4096);
_client.ReceiveAsync(_receiver);
break;
UPDATE 1 (adding code)
Server
public void Host()
{
_listener = new TcpListener(new IPEndPoint(IPAddress.Any, this.ConnectionPort));
_listener.Start();
this.IsListening = true;
ThreadPool.QueueUserWorkItem((state) =>
{
while (true)
{
// Blocks until a client connections occours
// If continue with no client then stop listening
try
{
TcpClient client = _listener.AcceptTcpClient();
// Add client to peer list
long assignedID = DateTime.UtcNow.Ticks;
_clients.Add(assignedID, client);
HandleClient(assignedID);
if (this.ConnectedClients == this.MaxClients)
{
_listener.Stop();
this.IsListening = false;
break;
}
}
catch
{
// Server has stop listening
_stopListen.Set();
break;
}
}
});
}
private void HandleClient(long assignedID)
{
ThreadPool.QueueUserWorkItem((state) =>
{
long clientID = (long)state;
TcpClient client = _clients[clientID];
try
{
byte[] message = new byte[4096];
byte[] buffer = new byte[4096];
int readed = 0;
int index = 0;
NetworkStream clientStream = client.GetStream();
while (true)
{
readed = clientStream.Read(message, 0, message.Length);
if (readed == 0)
{
// Client disconnected, thorw exception
throw new SocketException();
}
Array.Copy(message, 0, buffer, index, readed);
index += readed;
if (readed == 4096
&& !_packetHub.IsValidBufferData(buffer))
{
Array.Clear(buffer, 0, buffer.Length);
readed = 0;
index = 0;
continue;
}
if (_packetHub.IsValidBufferData(buffer))
{
NetPacket receivedPacket = _packetHub.DeserializePacket(buffer);
NetPacket answerPacket = null;
// Assign sender ID in case of unknown sender ID
if (receivedPacket.SenderID == NetPacket.UnknownID)
receivedPacket.SenderID = clientID;
// Handle received packet and forward answer packet
// to the client or to all other connected peers
answerPacket = HandlePacket(receivedPacket);
if (answerPacket != null)
{
if (answerPacket.RecipientID == clientID)
{
// Send answer packet to the client
SendPacket(client, answerPacket);
}
else
{
// Broadcast packet to all clients
foreach (TcpClient peer in _clients.Values)
SendPacket(peer, answerPacket);
}
}
// Reset receive packet buffer
Array.Clear(buffer, 0, buffer.Length);
readed = 0;
index = 0;
}
}
}
catch
{
System.Diagnostics.Debug.WriteLine("Network error occours!");
}
finally
{
// Close client connection
client.Close();
// Remove the client from the list
_clients.Remove(clientID);
// Raise client disconnected event
OnClientDisconnected();
}
}, assignedID);
}
Client
public void Connect()
{
if (this.ConnectionAddress == null)
throw new InvalidOperationException("Unable to connect. No server IP specified.");
_receiver = new SocketAsyncEventArgs();
_receiver.RemoteEndPoint = new IPEndPoint(this.ConnectionAddress, this.ConnectionPort);
_receiver.SetBuffer(new byte[4096], 0, 4096);
_receiver.Completed += new EventHandler<SocketAsyncEventArgs>(Socket_OperationComplete);
_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_client.ConnectAsync(_receiver);
}
private void Socket_OperationComplete(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Connect:
_readyToSend = true;
this.IsConnected = true;
// Once connection is estabilished, send a join packet to
// retrive server side assigned informations
JoinPacket joinPacket = (JoinPacket)NetPacket.CreatePacket(this.ClientID, NetPacket.ToHost, NetPacket.JoinPacket);
joinPacket.ClientName = this.ClientName;
joinPacket.ClientAddress = this.LocalAddress.ToString();
SendPacket(joinPacket);
break;
case SocketAsyncOperation.Receive:
_readyToSend = true;
byte[] buffer = _receiver.Buffer;
System.Diagnostics.Debug.WriteLine("Client received packet (" + _packetHub.GetBufferDataType(buffer) + ") with length of: " + buffer.Length);
if (_packetHub.IsValidBufferData(buffer))
{
NetPacket receivedPacket = _packetHub.DeserializePacket(buffer);
NetPacket answerPacket = null;
// Handle received packet and forward answer packet
// to the server
answerPacket = HandlePacket(receivedPacket);
if (answerPacket != null)
SendPacket(answerPacket);
}
else
{
_client.ReceiveAsync(_receiver);
}
break;
case SocketAsyncOperation.Send:
// Put in listen mode
_client.ReceiveAsync(_receiver);
break;
}
}
else
{
OnClientDisconnected();
System.Diagnostics.Debug.WriteLine(String.Format("Network error: {0}", e.SocketError.ToString()));
}
}
Since you are using TCP, you have to specify a port to send/listen (different for server and client). So no, it isn't normal (but it is if client and server are sending/listening on the same port).
Related
I'm working on a TCP communication program for the chemestry analyzer "Mindray BS240". The problem is that the analyzer keep disconnecting and reconnecting (every 30s). Here is my code, what did I miss ?
private void startTcpListner()
{
try
{
var port = settings.LisPort;
IPAddress localAddr = IPAddress.Parse(settings.LisIpAddress);
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
var bytes = new byte[256];
String data = null;
LogManager.GetCurrentClassLogger().Info("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also use server.AcceptSocket() here.
var client = server.AcceptTcpClient();
LogManager.GetCurrentClassLogger().Info("Connected !");
data = null;
// Get a stream object for reading and writing
stream = client.GetStream();
// Enter the listening loop.
while (true)
{
while (!stream.DataAvailable) ;
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
var line = Encoding.UTF8.GetString(bytes, 0, i);
LogManager.GetCurrentClassLogger().Info("Received: {0}", line);
data += line;
if (line.Length > 3 &&
line[line.Length - 2] == Hl7Helper.FileSeparator &&
line[line.Length - 1] == Hl7Helper.CarriageReturn)
{
handleMessage(data);
data = null;
}
}
}
}
catch (SocketException e)
{
LogManager.GetCurrentClassLogger().Error("SocketException: {0}", e);
}
catch (Exception e)
{
LogManager.GetCurrentClassLogger().Error(e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
}
In the log file, I have :
Waiting for a connection...
Connected !
So I am working on creating my own proxy server for my game server.
Whats happening so far is that I try to connect to my Terraria server and it says
Connecting..
Then I start my server application which accepts incoming requests on that specific IP & port and it prompts a MessageBox saying"Connected" and then the game goes from "Connecting..." to "Connecting to server..." but it gets stuck there, this is most likely because I am not redirecting the traffic from my proxy server to my server.. Right?
I've been trying to .Write() to the stream but I think I am writing to the wrong stream, do I write to the stream that accepts connections or do I create a new stream for outgoing traffic?
public partial class MainWindow : Window
{
public static IPAddress remoteAddress = IPAddress.Parse("127.0.0.1");
public TcpListener remoteServer = new TcpListener(remoteAddress, 7777);
public TcpClient client = default(TcpClient);
public TcpClient RemoteClient = new TcpClient("terraria.novux.ru", 7777);
public MainWindow()
{
InitializeComponent();
}
private void BtnListen_OnClick(object sender, RoutedEventArgs e)
{
if (StartServer())
{
client = remoteServer.AcceptTcpClient();
MessageBox.Show("Connected");
var receivedBuffer = new byte[1024];
//Should I write to this one instead?
var clientStream = client.GetStream();
var stream = RemoteClient.GetStream();
while (client.Connected)
if (client.Connected)
if (client.ReceiveBufferSize > 0)
{
receivedBuffer = new byte[1024];
stream.Write(receivedBuffer, 0, receivedBuffer.Length);
}
}
}
private bool StartServer()
{
try
{
remoteServer.Start();
MessageBox.Show("Server Started...");
return true;
}
catch (Exception exception)
{
MessageBox.Show(exception.ToString());
throw;
}
}
}
A simplified implementation could look like this.
public class Program
{
public static void Main(string[] args)
{
StartTcpListener("localhost", 9000);
}
private static byte[] SendReceiveRemoteServer(string host, int port, byte[] data)
{
try
{
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, port
// combination.
var client = new TcpClient(host, port);
// Get a client stream for reading and writing.
// Stream stream = client.GetStream();
var stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
Console.WriteLine("Sent to server: {0}", Encoding.ASCII.GetString(data));
// Receive the TcpServer.response.
// Read the first batch of the TcpServer response bytes.
var bytes = new byte[256];
var allBytes = new List<byte>();
var i = stream.Read(bytes, 0, bytes.Length);
// Loop to receive all the data sent by the client.
while (i != 0)
{
allBytes.AddRange(bytes);
bytes = new Byte[256];
i = stream.DataAvailable ? stream.Read(bytes, 0, bytes.Length) : 0;
}
Console.WriteLine("Received from server: {0}", Encoding.ASCII.GetString(data));
// Close everything.
stream.Close();
client.Close();
return allBytes.ToArray();
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: {0}", e);
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
Console.WriteLine("\n Press Enter to continue...");
return new byte[0];
}
private static void StartTcpListener(string host, int port)
{
TcpListener server = null;
try
{
var ipHostInfo = Dns.GetHostEntry(host);
var ipAddress = ipHostInfo.AddressList[0];
// TcpListener server = new TcpListener(port);
server = new TcpListener(ipAddress, port);
// Start listening for client requests.
server.Start();
// Enter the listening loop.
while (true)
{
Console.WriteLine("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
var client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
var stream = client.GetStream();
// Buffer for reading data
var bytes = new Byte[256];
var allBytes = new List<byte>();
var i = stream.Read(bytes, 0, bytes.Length);
// Loop to receive all the data sent by the client.
while (i != 0)
{
allBytes.AddRange(bytes);
bytes = new Byte[256];
i = stream.DataAvailable ? stream.Read(bytes, 0, bytes.Length) : 0;
}
if (allBytes.Count > 0)
{
Console.WriteLine("Received from client: {0}", Encoding.ASCII.GetString(allBytes.ToArray()));
var received = SendReceiveRemoteServer("localhost", 11000, allBytes.ToArray());
// Send back a response.
stream.Write(received, 0, received.Length);
Console.WriteLine("Sent to client: {0}", Encoding.ASCII.GetString(received));
}
// 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...");
}
}
Although improvements should be made:
make it async
make it work with multiple TcpClients at the same time
I am trying to listen for the client sending data multiple times. I do not know how to make the server listen to the client when the data is sent by the client a second time. For now i can send data by the client multiple times but the server will only accept the client data once. Please help.
Client
//the client
private TcpClient client = new TcpClient();
//constructor
public ClientConnect(string Ip, int Port)
{
IP = Ip;
PORT = Port;
}
//write the data to the server
public void Connect(byte[] clientId)
{
//try to connect to the server
Thread t = new Thread(() =>
{
while (true)
{
try
{
client.Connect(new IPEndPoint(IPAddress.Parse(IP), PORT));
break;
}
catch (SocketException)
{
Console.Clear();
Console.WriteLine("Trying to connect to the server...");
//pass if the connection failed
}
}
client.GetStream().Write(clientId, 0, (int)clientId.Length);
});
t.Start();
}
public void SendData(byte[] data)
{
Thread t2 = new Thread(() => {
while (true)
{
try
{
client.GetStream().Write(data, 0, (int)data.Length);
break;
}
catch (System.InvalidOperationException)
{
//pass
}
}
});
t2.Start();
}
Server:
while (true)
{
//Listen for a potential client
TcpClient client = tcpServer.AcceptTcpClient();
Console.WriteLine(client);
Console.WriteLine("Client connection accepted from " + client.Client.RemoteEndPoint + ".");
byte[] buffer = new byte[client.ReceiveBufferSize];
int bytesRead = client.GetStream().Read(buffer, 0, (int)buffer.Length);
byte[] buffer2 = new ArraySegment<byte>(buffer, 0, bytesRead).ToArray();
//do something with the data
}
I am using sockets for TCP-IP connection and I would like to establish simple system send-receive from the client side.
Socket sck;
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndpt = new IPEndPoint(IPAddress.Parse("123.123.123.1"), 12345);
try
{
sck.Connect(localEndpt);
}
catch
{
Console.Write("Unable to Connect");
}
while (true)
{
Console.WriteLine("Enter Text");
string sendtext = Console.ReadLine();
byte[] Data = Encoding.ASCII.GetBytes(sendtext);
sck.Send(Data);
Console.WriteLine("Data Sent!");
byte[] bytesReceived = new byte[sck.ReceiveBufferSize];
int bytes = 0;
String strReceived = "";
int dataAvailable = 0;
while (dataAvailable == 0 || dataAvailable != sck.Available)
{
dataAvailable = sck.Available;
Thread.Sleep(100); // if no new data after 100ms assume transmission finished
}
if (sck.Available > 0)
{
bytes = sck.Receive(bytesReceived, bytesReceived.Length, 0);
strReceived+=Encoding.ASCII.GetString(bytesReceived, 0, bytes);
}
Console.WriteLine("Received from server: " + strReceived);
}
Console.Read();
The problem is that first requests goes throught but the second does not, because socket is not available anymore (socket "Availabe" attribute value is 0). What am I doing wrong? What would be the easiest way to establish multiple send-recieve requests (in order)?
This code works fine for me
private List<Socket> _clients = new List<Socket>();
private Thread _dataReceiveThread;
private bool _isConnected;
private void DataReceive()
{
while (_isConnected)
{
List<Socket> clients = new List<Socket>(_clients);
foreach (Socket client in clients)
{
try
{
if (!client.Connected) continue;
string txt = "";
while (client.Available > 0)
{
byte[] bytes = new byte[client.ReceiveBufferSize];
int byteRec = client.Receive(bytes);
if (byteRec > 0)
txt += Encoding.UTF8.GetString(bytes, 0, byteRec);
}
if (!string.IsNullOrEmpty(txt))
/* TODO: access the text received with "txt" */
}
catch (Exception e)
{
Exception_Handler(e);
}
}
}
}
Just run this code to get started
_isConnected = true;
_dataReceiveThread = new Thread(DataReceive);
_dataReceiveThread.Start();
Update list box in Cross thread:
This code can be placed in the comment section.
myListBox1.Invoke((Action)(() => { myListBox1.Items.Add(txt) }));
Socket. Available does NOT indicate whether the socket is available, but incoming data is available for reading:
https://msdn.microsoft.com/en-us/library/ee425135.aspx
Your program quits because it checks for a reply (incoming data) immediately after sending a message out. Use a Thread.Sleep before checking for data.
Maybe the message has not even been sent, because Socket.Send just places it in the network interface card's output buffer. When the socket finally sends the message, it will upare the connection state. If it got no reply (on a TCP connection), it will tell you that it is disconnected when you query the state. On UDP it will tell you nothing, because UDP is connectionless.
I just read and tested code of this great article in order to understand TCP Client and Server.
Now I need to do (I hope) really simple thing I need to send some string from TCP Client To TCP Server.
The string is serialized object and it is a XML in fact.
What I don't understand where I have to include this code in TCP Client and also in the TCP server.
TCP Client:
static void Main(string[] args)
{
while (true)
{
String server = "192.168.2.175"; // args[0]; // Server name or IP address
// Convert input String to bytes
byte[] byteBuffer = Encoding.ASCII.GetBytes("1024"); // Encoding.ASCII.GetBytes(args[1]);
// Use port argument if supplied, otherwise default to 8080
int servPort = 1311; // (args.Length == 3) ? Int32.Parse(args[2]) : 8080;//7 ;
TcpClient client = null;
NetworkStream netStream = null;
try
{
// Create socket that is connected to server on specified port
client = new TcpClient(server, servPort);
Console.WriteLine("Connected to server... sending echo string");
netStream = client.GetStream();
// Send the encoded string to the server
netStream.Write(byteBuffer, 0, byteBuffer.Length);
Console.WriteLine("Sent {0} bytes to server...", byteBuffer.Length);
int totalBytesRcvd = 0; // Total bytes received so far
int bytesRcvd = 0; // Bytes received in last read
// Receive the same string back from the server
while (totalBytesRcvd < byteBuffer.Length)
{
if ((bytesRcvd = netStream.Read(byteBuffer, totalBytesRcvd,
byteBuffer.Length - totalBytesRcvd)) == 0)
{
Console.WriteLine("Connection closed prematurely.");
break;
}
totalBytesRcvd += bytesRcvd;
}
Console.WriteLine("Received {0} bytes from server: {1}", totalBytesRcvd,
Encoding.ASCII.GetString(byteBuffer, 0, totalBytesRcvd));
}
catch (Exception ex)
{
// http://stackoverflow.com/questions/2972600/no-connection-could-be-made-because-the-target-machine-actively-refused-it
Console.WriteLine(ex.Message);
}
finally
{
if (netStream != null)
netStream.Close();
if (client != null)
client.Close();
}
Thread.Sleep(1000);
}
}
TCP Server
class Program
{
private const int BUFSIZE = 32; // Size of receive buffer
static void Main(string[] args)
{
int servPort = 1311; // (args.Length == 1) ? Int32.Parse(args[0]) : 8080;
TcpListener listener = null;
try
{
// Create a TCPListener to accept client connections
listener = new TcpListener(IPAddress.Any, servPort);
listener.Start();
}
catch (SocketException se)
{
// IPAddress.Any
Console.WriteLine(se.ErrorCode + ": " + se.Message);
//Console.ReadKey();
Environment.Exit(se.ErrorCode);
}
byte[] rcvBuffer = new byte[BUFSIZE]; // Receive buffer
int bytesRcvd; // Received byte count
for (; ; )
{ // Run forever, accepting and servicing connections
// Console.WriteLine(IPAddress.Any);
TcpClient client = null;
NetworkStream netStream = null;
//Console.WriteLine(IPAddress.None);
try
{
client = listener.AcceptTcpClient(); // Get client connection
netStream = client.GetStream();
Console.Write("Handling client - ");
// Receive until client closes connection, indicated by 0 return value
int totalBytesEchoed = 0;
while ((bytesRcvd = netStream.Read(rcvBuffer, 0, rcvBuffer.Length)) > 0)
{
netStream.Write(rcvBuffer, 0, bytesRcvd);
totalBytesEchoed += bytesRcvd;
}
Console.WriteLine("echoed {0} bytes.", totalBytesEchoed);
// Close the stream and socket. We are done with this client!
netStream.Close();
client.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
netStream.Close();
}
}
}
}
Converting my Comments into an answer:
I strongly suggest you use WCF, instead of implementing all the stuff yourself. In WCF, you create the interfaces (Service Contracts) and implementations (Services) and the framework abstracts all the communication / protocol details out.
You can use WCF Duplex to have two-way communications between server and client
The example that you give is a simple 'mirror', where the TCP server sends back to the client the data that it receives from it.
The data that you want to send is in the byteBuffer variable (you are currently sending the text "1024", I believe). So instead of initializing it with "1024", you could initialize it with the XML-serialized data that you want.
On the client side, conversely, instead of echoing the data back to the client, you could simply do whatever you need on the server side with the data, that is your XML object.