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.
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 !
I am having a problem sending information down a socket and receiving a response. I have a demo program which is performing correctly so I know it is not an issue with the client on the other end.
The requestData is sent and the client acts correctly and responds, but my code never exits the loop in read response.
Could the client be responding before I am listening? How can I make sure I never miss an incoming message?
networkStream = tcpClient.GetStream();
StreamWriter clientStreamWriter = new StreamWriter();
clientStreamWriter.WriteLine(requestData);
clientStreamWriter.Flush();
// Continuously read data on the socket and if it is more than just a ping, read the response.
StringBuilder sbReadBuffer = new StringBuilder();
while (true)
{
String response = readresponse(timeoutOn30Seconds);
if (response.Length > 1 && (!response.Contains("\r\n") || response.Contains(",")))
{
break;
}
}
sbReadBuffer.Append(received);
return sbReadBuffer.ToString();
readResponse:
private string readresponse(Boolean timeoutOn30Seconds)
{
// Get network stream.
DateTime lastConTime = DateTime.Now;
Int32 i = 0;
// Start listening to stream.
while (!networkStream.DataAvailable)
{
Log.W(".");
// Only check every 10ms.
Thread.Sleep(10);
// If no response in 30mins stop listening and give an offline warning.
if ((DateTime.Now - lastConTime).TotalSeconds > tcpClient.ReceiveTimeout)
{
received = "CLIENT NOT FOUND";
return received;
}
// Only check if application online every 1s.
if (i > 100)
{
if (Process.GetProcessesByName(ConfigurationManager.AppSettings["ClientName"]).FirstOrDefault() == null && Convert.ToInt32(ConfigurationManager.AppSettings["Device"]) != 680)
{
received = "CLIENT NOT FOUND";
return received;
}
i = 0;
}
i++;
}
// If data has been writted to the buffer, read it out and assign output variable and return that string for length comparison.
byte[] receiveBuffer = new byte[tcpClient.ReceiveBufferSize];
Int32 receiveCount = networkStream.Read(receiveBuffer, 0, receiveBuffer.Length);
received = new ASCIIEncoding().GetString(receiveBuffer, 0, receiveCount);
return received;
}
DataAvailable isn't a good method to know if data are coming, especially in a while loop that is surely faster than network communications.
A better way could be to use the Read method (bytes read) to know where data are available, into a timed loop; so change your while condition in this manner (and then adjust the other parts)
while (networkStream.Read(receiveBuffer, 0, receiveBuffer.Length) > 0)
{
Log.W(".");
// Only check every 10ms.
Thread.Sleep(10);
but I prefer, if possible, an async approach, so your client will be notified when data are incoming.
See this answer that use this kind of approach.
Basically set an async callback that will be fired when data are coming
public void StartListening() {
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0],11000);
Console.WriteLine("Local address and port : {0}",localEP.ToString());
Socket listener = new Socket( localEP.Address.AddressFamily,
SocketType.Stream, ProtocolType.Tcp );
try {
listener.Bind(localEP);
listener.Listen(10);
while (true) {
allDone.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(SocketListener.acceptCallback),
listener );
allDone.WaitOne();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
Console.WriteLine( "Closing the listener...");
}
and there you can read your data
public static void acceptCallback(IAsyncResult ar) {
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Signal the main thread to continue.
allDone.Set();
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(AsynchronousSocketListener.readCallback), state);
}
Here full MSDN documentation
You dont read in while loop. To clear DataAvailable flag, you have to read from networkStream.
Sample usage :
http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.dataavailable%28v=vs.100%29.aspx
I send 2 successive packets from my client to the server who is listening using BeginReceive
The server always receives the first packet but not the other EXCEPT if I run the client in debug mode and slowly send the next packet after the other.
Here's a snippet from my sending function
if (soc.Connected)
{
byte[] byData = new byte[System.Text.Encoding.ASCII.GetByteCount("Hi")];
byData = System.Text.Encoding.ASCII.GetBytes("Hi");
soc.Send(BitConverter.GetBytes(byData.Length));
soc.Send(byData);
}
And here's is my call back function located inside of my server:
private void Recieve(IAsyncResult iar)
{
int j = 0;
Socket server_conn = (Socket)iar.AsyncState;
server_conn.EndReceive(iar);
if (!SocketConnected(server_conn))
{
server_conn.Close();
return;
}
if (g_bmsg.Length != 0)
{
logthis(server_conn.RemoteEndPoint.ToString() + ": " + Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));
}
//Find out who sent this
foreach (ClientData cls in clientlist)
{
if (server_conn.RemoteEndPoint == cls.clientsock.RemoteEndPoint)
{
j = cls.index;
break;
}
}
server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), server_conn);
}
When working with TCP/IP sockets (or pretty much any communication layer), you rarely have a guarantee that the entire message you intended to send will come in a single packet.
This means that you should always keep a FIFO buffer of your own, and parse it sequentially.
This is the general idea:
// fifo queue (for background thread parsing, make sure it's thread safe)
private readonly ConcurrentQueue<byte> _commQueue = new ConcurrentQueue<byte>();
In your Receive method, you should simply enqueue the data to the FIFO:
private void Receive(IAsyncResult iar)
{
Socket server_conn = (Socket)iar.AsyncState;
// check how many bytes we actually received
var numBytesReceived = server_conn.EndReceive(iar);
if (!SocketConnected(server_conn))
{
server_conn.Close();
return;
}
// get the received data from the buffer
if (numBytesReceived > 0)
{
for (int i = 0; i < numBytesReceived; i++)
_commQueue.Enqueue(g_bmsg[i]);
// signal the parser to continue parsing
NotifyNewDataReceived();
}
// continue receiving
server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), server_conn);
}
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.
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).