Reading a Protobuf Message in C# - c#

I have a simple message:
package test;
message sendName {
optional string username = 1;
}
The awesome VS plugin generates the .cs file:
namespace test {
[global::System.Serializable global::ProtoBuf.ProtoContract(Name=#"sendName")]
public partial class sendName : global::ProtoBuf.IExtensible {
public sendName() {}
private string _username = "";
[global::ProtoBuf.ProtoMember(1, IsRequired = false, Name=#"username", DataFormat = > global::ProtoBuf.DataFormat.Default)]
[global::System.ComponentModel.DefaultValue("")]
public string username
{
get { return _username; }
set { _username = value; }
}
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{
return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
}
}
}
I am sending a message from the java side by using
objName.build().writeTo((FileOutputStream)socket.getOutputStream());
In my C# application, which acts like the Socket Listener, I have a method called Listen which listens for the message sent by the java client:
public void Listen()
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(ipAddress, 4055);
TcpClient client = null;
listener.Start();
while (true)
{
Debug.WriteLine("Waiting for a Connection");
client = listener.AcceptTcpClient();
Stream stream = client.GetStream();
// sendName sendNameObj = Serializer.Deserialize<sendName>(stream);
}
}
I am obviously missing some basics here.
What method should I use to get the sendName object?
When I debug my code in C#, the debugger quits when I call DeserializeWithLengthPrefix method.
This is my C# code:
private void Listen()
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(ipAddress,4055);
listener.Start();
listener.BeginAcceptSocket(ClientConnected, listener);
}
private void ClientConnected(IAsyncResult result)
{
TcpListener server = (TcpListener)result.AsyncState;
using (TcpClient client = server.EndAcceptTcpClient(result))
using (NetworkStream stream = client.GetStream())
{
try
{
//SendNameMessage sendNameObj = Serializer.Deserialize<SendNameMessage>(stream);
SendNameMessage sendNameObj = Serializer.DeserializeWithLengthPrefix<SendNameMessage>(stream, PrefixStyle.Fixed32);
string name = sendNameObj.sendName;
if (name != null && name.Length > 0)
{
nameTextBox.Text = name;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
This is my java code:
SendNameMessage.Builder sendNameMessageObj = null;
sendNameMessageObj = SendNameMessage.newBuilder();
sendNameMessageObj.setSendName("Protobuf-net");
SocketRequest.INSTANCE.openSocket();
sendNameMessageObj.build().writTo(SocketRequest.INSTANCE.getWriter());

The Serializer.Deserialize<sendName>(stream); should do it, but I'm guessing that it is hanging forever? The reason here is that protobuf messages don't have an inbuilt terminator, so the default is that it reads until the end of the stream - which won't happen until you close the socket.
To get around this, a common trick is to prefix the message with the length, and limit yourself to that. There may be an inbuilt way to handle that in the Java implementation, or you can handle it manually. On the C# side, protobuf-net has DeserializeWithLengthPrefix, which accepts an enum to specify how you've encoded it. For simplicity I would suggest a basic 32-bit little-endian encoding of the length (which maps to PrefixStyle.Fixed32).
Re the edit / comment: the two must match. At the moment you are serializing without a length prefix, but deserializing expecting a length prefix. Does the Java API expose a mechanism to obtain the data-length before you write it? If not, perhaps write first to a temp buffer, see how much you wrote, then write the length and finally the data.
Or; if you are only sending a single message - just close the stream and use Deserialize (no length prefix). I have a C#-to-C# multi-message sockets example available, but I can't comment much on the java side...

Related

Convert TCP StreamReader/StreamWriter to SSLStream

Here is my code:
public class ServerClient
{
public TcpClient tcp;
public StreamReader streamReader;
public StreamWriter streamWriter;
public int accountId;
public int connectionId;
public ServerClient(TcpClient clientSocket)
{
tcp = clientSocket;
streamReader = new StreamReader(tcp.GetStream(), false);
streamWriter = new StreamWriter(tcp.GetStream());
clientSocket.NoDelay = true;
}
}
Here is how i am listening for data, this is called in a while loop:
// Check for message from Client.
NetworkStream s = c.tcp.GetStream();
if (s.DataAvailable)
{
string data = c.streamReader.ReadLine();
if (data != null)
{
if (ValidateJSON(data))
{
OnIncomingData(c, data);
}
}
}
//continue;
Here is how i check if the client is still connected:
private bool IsConnected(TcpClient c)
{
try
{
if (c != null && c.Client != null && c.Client.Connected)
{
if (c.Client.Poll(0, SelectMode.SelectRead))
{
return !(c.Client.Receive(new byte[1], SocketFlags.Peek) == 0);
}
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
Here is how i send data into the stream:
string JSonData = JsonConvert.SerializeObject(SendData);
c.streamWriter.WriteLine(JSonData);
c.streamWriter.Flush();
Here is my client how it listens for message:
public void ConnectToWorldServer()
{
if (socketReady)
{
return;
}
//Default host and port values;
string host = "127.0.0.1";
int port = 8080;
//ClientLoginServer ClientLoginServer = new ClientLoginServer();
try
{
socket = new TcpClient(host, port);
stream = socket.GetStream();
socket.NoDelay = true;
writer = new StreamWriter(stream);
reader = new StreamReader(stream);
socketReady = true;
//Preserve the connection to worldserver thrue scenes
UnityThread.executeInUpdate(() =>
{
DontDestroyOnLoad(worldserverConnection);
});
// Start listening for connections.
while (true)
{
keepReading = true;
while (keepReading)
{
keepReading = true;
if (socketReady)
{
if (stream.DataAvailable)
{
string data = reader.ReadLine();
if (data != null)
{
UnityThread.executeInUpdate(() =>
{
OnIncomingData(data);
});
}
}
}
System.Threading.Thread.Sleep(1);
}
System.Threading.Thread.Sleep(1);
}
}
catch (Exception e)
{
Debug.Log("Socket error : " + e.Message);
}
}
I have red about SSL Stream. Here is what i have found: https://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx
I have several questions:
Do i need to buy an SSL certificate like a certificate for a website ?
Can i generate a self-signed SSL certificate? If so and it's needed can you show me any reference of how to achieve that ?
Is it possible to attach this SSL Stream to my StreamReader/StreamWriter ? Is it even needed or i have to remake the whole connection/communication thing?
When SSLStream is created the whole communication between the server and the client will be encrypted so anybody can't stay in between and listen/understand what they are communicating ?
If i have to attach a certificate file to the client so it may establish a successful SSL connection to the server and then send that client to all the people which have to use that client, doesn't that compromise the security of the SSL connection as i am sending them the certificate as well ?
This is all i wanted to ask. The best thing you can do to help me with your answer is if possible please put the code changes i have to apply in order to make that StreamReader/StreamWriter work over encrypted SSL.
you need a certificate; makecert would work, but it won't be trusted by default, so you'd either need to supply a custom RemoteCertificateValidationCallback to the consumer, or use a trusted cert; Let's Encrypt might be useful there
makecert or New-SelfSignedCertificate
the SslStream would need to go between the NetworkStream and the StreamReader; frankly, it isn't clear to make that StreamReader give you much here - you could do everything here with just the Streaam API; so instead of WriteLine, you'd encode manually and then Write the encoded buffer; but - there's no reason that you can't just whack SslStream in the middle of the two
yes
only the server needs the certificate (and in particular, only the server needs the private key of the certificate); there is something related called "client certificates" used for authenticating the client, but that is a related but different topic
As an example ripped from SE.Redis and mangled beyond legibility; SE.Redis optionally encrypts, and is basically:
Stream stream = // connect (get a NetworkStream)
if (config.Ssl) {
var ssl = new SslStream(stream, ... cert check callbacks, etc ...);
ssl.AuthenticateAsClient(expectedHost, allowedSslProtocols);
stream = ssl;
}
so it you had something like that, you'd just make sure you attached any StreamReader/StreamWriter after you've wrapped the NetworkStream in SslStream. But again: I really think you could remove StreamReader/StreamWriter here without much inconvenience.

EndRead throws IO exception

This is for local communication between a MoSync application and an external DLL, MoSync does not allow me to use 3rd part DLLs and that is the reason why I have to implement this bridge software instead of using a simple call to a DLL, I have to convert from xml to the DLL Message format, and again to XML. I know this is a dumb thing, unfortunately there is no flexibility to change the architecture. Initially i thought that there was only one request so I had Sync coms but now I find out there can be more than one request, so I need to implement Async back again.
I have an exception that is thrown from time to time, since I am new to C# I am unable to find the memory leak... perhaps a pair of more well trained eyes can find the issue
SOURCE CODE:
I have written the following code, I am quite new to C# and Sockets, so perhaps I have made some big mistakes that only more experienced eyes can detect. This is to be used in a Windows Mobile 6.1 device, so I am trying to avoid using many threads.
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Diagnostics;
namespace SmartDevice_Server
{
//ClientConnection saves connection information is used to keep context in Async and Event calls
public class ClientConnection : EventArgs
{
public NetworkStream NetworkStream { get; private set; }
public byte[] Data { get; private set; }
public int byteReadCount { get; set; }
public ClientConnection(NetworkStream networkStream, byte[] data)
{
NetworkStream = networkStream;
Data = data;
}
}
//MySocket - Is a server that listens for events and triggers Events upon Request Completion
public class MySocketTCP
{
#region Class Members
TcpListener myTcpListener;
TcpClient myTcpClient;
NetworkStream myNetworkStream;
const string localHost = "127.0.0.1";
IPAddress myAddress = IPAddress.Parse(localHost);
int myPortNumber = 58889;
byte[] myData;
int bytesReadCount;
const int MIN_REQUEST_STRING_SIZE = 10;
int TimeStart;
//Event
public event socketReadCompleteHandler socketReadCompleteEvent;
public EventArgs eventArguments = null;
public delegate void socketReadCompleteHandler(MySocketTCP myTcpSocket, ClientConnection eventArguments);
#endregion
//Constructor
public MySocketTCP()
{
Init();
}
//Constructor overloaded to receive IPAdress Host, and Port number
public MySocketTCP(IPAddress hostAddress, int portNumber)
{
myAddress = hostAddress;
myPortNumber = portNumber;
Init();
}
//Initializes the TCPListner
public void Init()
{
try
{
myTcpListener = new TcpListener(myAddress, myPortNumber);
//myNetworkStream = myTcpClient.GetStream();
}
catch (Exception ex)
{
throw ex;
}
}
/*TODO_Listener_Timer: After you accept a connection you wait for data to be Read indefinitely
*Possible solution: Use a timeout to close the socket connection.
*Check WIKI, TODOS
* */
//Listens Asynchronously to Clients, class a recieveMessageHandler to process the read
public void ListenAsync()
{
myTcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
myTcpClient = myTcpListener.AcceptTcpClient();
var client = new ClientConnection(myTcpClient.GetStream(), new byte[myTcpClient.ReceiveBufferSize]);
// Capture the specific client and pass it to the receive handler
client.NetworkStream.BeginRead(client.Data, 0, client.Data.Length, r => receiveMessageHandler(r, client), null);
}
}
//Callback is used to Process the request Asynchronously, triggers socketReadCompleteEvent
public void receiveMessageHandler(IAsyncResult asyncResult, ClientConnection clientInstance)
{
bytesReadCount = 0;
lock (clientInstance.NetworkStream)
{
try
{
bytesReadCount = clientInstance.NetworkStream.EndRead(asyncResult);
clientInstance.byteReadCount = bytesReadCount;
}
catch (Exception exc)
{
throw exc;
}
}
if (bytesReadCount < MIN_REQUEST_STRING_SIZE)
{
//Could not read form client.
Debug.WriteLine("NO DATA READ");
}
else
{
if (socketReadCompleteEvent != null)
{
socketReadCompleteEvent(this, clientInstance);
}
}
}
//Reads the request, uses the ClientConnection for context
public string ReadAsync(ClientConnection connObj)
{
int bytesReadCount = connObj.byteReadCount;
byte[] myData = connObj.Data;
string xmlMessage;
try
{
xmlMessage = Encoding.ASCII.GetString(myData, 0, bytesReadCount);
}
catch (Exception ex)
{
throw ex;
}
return xmlMessage;
}
//Deprecated
public string Read()
{
string xmlMessage;
try
{
xmlMessage = Encoding.ASCII.GetString(myData, 0, bytesReadCount);
}
catch (Exception ex)
{
throw ex;
}
return xmlMessage;
}
//Deprecated
public void Write(byte[] outBytes)
{
try
{
myNetworkStream.Write(outBytes, 0, outBytes.Length);
}
catch (Exception ex)
{
throw ex;
}
}
//Deprecated
public void Write(string outMessage)
{
byte[] outBytes = Encoding.ASCII.GetBytes(outMessage);
try
{
myNetworkStream.Write(outBytes, 0, outBytes.Length);
}
catch (Exception ex)
{
throw ex;
}
int TimeEnd = Environment.TickCount;
int TimeResult = TimeEnd - TimeStart;
}
//Is used to send the message to the correct socket
public void WriteAsync(ClientConnection connObj, string outMessage)
{
byte[] outBytes = Encoding.ASCII.GetBytes(outMessage);
try
{
connObj.NetworkStream.Write(outBytes, 0, outBytes.Length);
}
catch (Exception ex)
{
throw ex;
}
int TimeEnd = Environment.TickCount;
int TimeResult = TimeEnd - TimeStart;
}
//Closes the client
public void Close()
{
//myNetworkStream.Close();
try
{
myTcpClient.Close();
}
catch (Exception ex)
{
throw ex;
}
}
}
}
The most likely problem is that you are expecting to do exactly three "reads" for the three "writes" that client did.
This is a wrong assumption since TCP socket is a byte stream and does not preserve your application message boundaries. The server might consume those three "messages" sent by the client in one, or two, or seventeen reads.
You need to tell the server somehow where the message ends in the byte stream. Usual choices are fixed length messages, delimiters, message headers that tell length of the payload, self-describing formals like XML, etc.
So you continue reading from the stream until you have a complete message for processing, but at the same time you might have a part of the next message already read into your buffer.
I think the problem here is that you're only holding a single NetworkStream (myNetworkStream) as such, if a second client connects before the first has sent data, your accept loop will overwrite myNetworkStream with the stream for the 2nd connection. When the first client then sends some data your receiveMessageHandler will call EndRead on the 2nd connection's NetworkStream (which was stored in myNetworkStream when the 2nd client connected), but passing in the asyncResult from the 1st client's read. This causes the exception you indicate. Specifically when I tested it, I got the following message:
Unable to read data from the transport connection: The IAsyncResult object was not returned from the corresponding asynchronous method on this class.
Parameter name: asyncResult.
Try making the following changes:
// Create a class to hold details related to a client connection
public class ClientConnection
{
public ClientConnection(NetworkStream networkStream, byte[] data)
{
NetworkStream = networkStream;
Data = data;
}
public NetworkStream NetworkStream { get; private set; }
public byte[] Data { get; private set; }
}
public void Listen()
{
myTcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
myTcpClient = myTcpListener.AcceptTcpClient();
var client = new ClientConnection(myTcpClient.GetStream(), new byte[myTcpClient.ReceiveBufferSize]);
// Capture the specific client and pass it to the receive handler
client.NetworkStream.BeginRead(client.Data, 0, client.Data.Length, r => receiveMessageHandler(r, client), null);
}
}
public void receiveMessageHandler(IAsyncResult asyncResult, ClientConnection client)
{
var byteReadCount = client.NetworkStream.EndRead(asyncResult);
if (byteReadCount < MIN_REQUEST_STRING_SIZE)
{
//Could not read form client.
//Erro - Como tratar? Close()
}
else
{
if (socketReadCompleteEvent != null)
{
socketReadCompleteEvent(this, eventArguments);
}
}
}
As others have mentioned, there are additional issues related to your expectations of matched reads/writes between sender and receiver, but this seems to be the cause of the actual issue you're seeing.
Edit:
Here's a server that will receive data, and call a callback method when a full message is received. The callback returns a string, which is then sent back to the client, which calls its own replyCallback with the response data. Only a single request-response is sent per connection (which is rather inefficient, but should serve as a good starting point).
public static class Server
{
public static void Run(int port, Action<string> callback)
{
var listener = new TcpListener(IPAddress.Loopback, port);
listener.Start();
while (true)
{
using (var client = listener.AcceptTcpClient())
{
try
{
var buffer = new byte[2048];
using (var memoryStream = new MemoryStream())
{
using (var stream = client.GetStream())
{
stream.ReadTimeout = 1000; // 1 second timeout
int bytesRead;
// Loop until Read returns 0, signalling the socket has been closed
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buffer, 0, bytesRead);
}
}
// Pass the client's message to the callback and use the response as the reply message to the client.
var reply = Encoding.UTF8.GetBytes(callback(Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length)));
stream.Write(reply, 0, reply.Length);
}
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e.Message);
}
}
}
}
}
Here's a small client program that will connect, send its data and wait for a response. Once the response is received, it will pass call replyCallback with the server's response:
public static class Client
{
public static void Run(string hostname, int port, string dataToSend, Action<string> replyCallback)
{
using (var client = new TcpClient(hostname, port))
{
using (var stream = client.GetStream())
{
var buffer = Encoding.UTF8.GetBytes(dataToSend);
stream.Write(buffer, 0, buffer.Length);
// Shutdown the send side of the socket, indicating to the server we're done sending our message
client.Client.Shutdown(SocketShutdown.Send);
using (var memoryStream = new MemoryStream())
{
stream.ReadTimeout = 1000; // 1 second timeout
int bytesRead;
// Loop until Read returns 0, signalling the socket has been closed
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buffer, 0, bytesRead);
}
replyCallback(Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length));
}
}
}
}
}
And a small test-harness to tie it all together:
static class Program
{
static void Main(string[] args)
{
var port = 12345;
ThreadPool.QueueUserWorkItem(o => Server.Run(port, ProcessClientMessage));
while (true)
{
Console.WriteLine("Enter a message to send and hit enter (or a blank line to exit)");
var data = Console.ReadLine();
if (string.IsNullOrEmpty(data)) break;
Client.Run("localhost", port, data, m => Console.WriteLine("Client received server reply: {0}", m));
}
}
private static string ProcessClientMessage(string clientMessage)
{
Console.WriteLine("Server received client message: {0}", clientMessage);
// This callback would ordinarily process the client message, then return a string that will be sent back to the client in response.
// For now, we'll just return a fixed string value...
return "This is the server reply...";
}
}

Incomplete messages (C# TCP/IP Client)

First of all, I'm absolutely not a network programmer. What I try to do, is a very simple TCP/IP communication between a Java server and a C# client.
Java server:
public void run(){
try {
// Open server socket
_server = new ServerSocket(SERVER_PORT);
_client = _server.accept();
System.out.println("ComInterface: client connected.");
// Wait for a client data output stream
while(true){
// Receive message from client
BufferedReader is =
new BufferedReader(new InputStreamReader(_client.getInputStream()));
msg = is.readLine();
// Process message
if(msg!=null){
System.out.println("ComInterface: Message Received : <" + msg + ">.");
processMessage(msg); // Independant method
}
else{
System.out.println("ComInterface: client closed connection.");
_client.close();
_client = _server.accept();
System.out.println("ComInterface: client connected.");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String msg){
try {
// Out stream
DataOutputStream os = new DataOutputStream(_client.getOutputStream());
os.writeBytes((String)(msg+"\n"+(char)13));
os.flush();
System.out.println("ComInterface: Message <" + msg + "> sent");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And here's the C# client:
public class ComInterface : MonoBehaviour
{
public const String SERVER_IP = "127.0.0.1"; // Localhost
public const int PORT = 1100; // Default port
public const int READ_BUFFER_SIZE = 5000; // 4.8828125 kilobytes
private TcpClient _client;
private ASCIIEncoding _asen;
private byte[] _readBuffer;
private String _msg;
public Boolean connected { get; internal set; } // setter is for internal use only
/**
* Initialize internal variables (buffer, socket...)
*/
public ComInterface()
{
connected = false;
_client = new TcpClient();
_asen = new ASCIIEncoding();
_readBuffer = new Byte[READ_BUFFER_SIZE];
_msg = String.Empty;
}
/**
* Connect to server at SERVER_IP:PORT
* Return true if connection was a success, or false if failure.
*/
public Boolean Connect()
{
try
{
_client.Connect(SERVER_IP, PORT);
connected = true;
Array.Clear(_readBuffer, 0, _readBuffer.Length);
Debug.Log("TCPClient: <Connect> Connected to the server");
// Start an asynchronous read invoking ReceiveComMessage
_client.GetStream().BeginRead(_readBuffer, 0, READ_BUFFER_SIZE, new AsyncCallback(ReceiveComMessage), _client.GetStream());
}
catch (Exception ex)
{
Debug.Log("TCPClient: <Connect> Cannot connect to the server - " + ex.Message);
connected = false;
}
// Return connection state
return connected;
}
/**
* Received a message from Communicator
*/
private void ReceiveComMessage(IAsyncResult ar)
{
int BytesRead;
String msg;
try
{
BytesRead = _client.GetStream().EndRead(ar);
if (BytesRead < 1)
{
// if no bytes were read server has close.
Debug.Log("TCPClient: <ReceiveComMessage> The server has closed (BytesRead<1)");
this.Disconnect();
return;
}
// Convert the byte array the message was saved into,
msg = Encoding.ASCII.GetString(_readBuffer);
Debug.Log("C# Message: \"" + msg + "\""); // Output example in log below
BytesRead = 0;
Array.Clear(_readBuffer, 0, _readBuffer.Length);
// Start a new asynchronous read into readBuffer.
_client.GetStream().BeginRead(_readBuffer, 0, READ_BUFFER_SIZE, new AsyncCallback(ReceiveComMessage), _readBuffer);
}
catch (Exception ex)
{
Debug.Log("TCPClient: <ReceiveComMessage> The server has closed (Exception):" + ex.Message + " see " + ex.StackTrace);
this.Disconnect();
}
The main problem is that all the message are arriving incomplete. Here's the log trace:
C#: Message "{
C#: Message ""sender":"Bob"",
C#: Message ""recipient":",
etc...
Instead of for instance
C#: Message "{"sender":"Bob","recipient":[1,2,3]}"
I'm a bit confused and I'd need some help to resolve this. Thank you very much!
TCP is a stream-oriented connection, not message-oriented. It has no concept of a message. When you write out your serialized string, it only sees a meaningless sequence of bytes. TCP is free to break up that stream up into multiple fragments and they will be received at the client in those fragment-sized chunks. It is up to you to reconstruct the entire message on the other end.
In your scenario, one would typically send a message length prefix. This way, the client first reads the length prefix so it can then know how large the incoming message is supposed to be.
I would seriously consider using something like Google's Protocol Buffers as a good way of declaring your messages and then streaming them with the size prefix option. The nice thing is that you define your set of messages once and then use the available tools to automatically generate C++, Java, C#, etc code from the message definitions. This will help in having a consistent messaging set that works between languages.
A message (any data, I mean), when sent through a socket, is divided into several packets.
When printing each received packet, you don't see your whole message.
You should define an end of message string (something like ".#."). Until you receive this sequence, you keep concatenating the messages you receive.
This is what session protocols (that is, protocols that run on the top of TCP) do.
Hope this helps.
Regards, Calil
Take a look at this example...
Java TCP Server...
import java.net.*;
import java.io.*;
public class TcpServer
{
public static void main(String h[])
{
try
{
ServerSocket serverSocket = new ServerSocket(1100);
Socket socket = serverSocket.accept();
System.out.println("Client Accepted");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("Received: " + bufferedReader.readLine());
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
printWriter.println("Hello Theo. Welcome to socket programming.");
} catch (Exception e)
{
System.out.println(e);
}
}
}
C# TCP Client...
using System;
using System.IO;
using System.Net.Sockets;
class Program
{
static void Main(string[] args)
{
try
{
var client = new TcpClient("localhost", 1100);
var stream = client.GetStream();
var streamWriter = new StreamWriter(stream);
streamWriter.WriteLine("My name is Theo");
streamWriter.Flush();
var streamReader = new StreamReader(stream);
Console.WriteLine("Received: " + streamReader.ReadLine());
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.WriteLine("Press a key to continue.");
Console.ReadKey();
}
}

Sending and receiving data over a network using TcpClient

I need to develop a service that will connect to a TCP server. Main tasks are reading incoming messages and also sending commands to the server in ten minutes, like a synchronize command. For example, I used the TcpClient object as shown below:
...
TcpClient tcpClient = new TcpClient();
tcpClient.Connect("x.x.x.x", 9999);
networkStream = tcpClient.GetStream();
clientStreamReader = new StreamReader(networkStream);
clientStreamWriter = new StreamWriter(networkStream);
while(true)
{
clientStreamReader.Read()
}
Also, when I need to write out something in any method, I use:
clientStreamWriter.write("xxx");
Is this usage correct? Or is there a better way?
First, I recommend that you use WCF, .NET Remoting, or some other higher-level communication abstraction. The learning curve for "simple" sockets is nearly as high as WCF, because there are so many non-obvious pitfalls when using TCP/IP directly.
If you decide to continue down the TCP/IP path, then review my .NET TCP/IP FAQ, particularly the sections on message framing and application protocol specifications.
Also, use asynchronous socket APIs. The synchronous APIs do not scale and in some error situations may cause deadlocks. The synchronous APIs make for pretty little example code, but real-world production-quality code uses the asynchronous APIs.
Be warned - this is a very old and cumbersome "solution".
By the way, you can use serialization technology to send strings, numbers or any objects which are support serialization (most of .NET data-storing classes & structs are [Serializable]).
There, you should at first send Int32-length in four bytes to the stream and then send binary-serialized (System.Runtime.Serialization.Formatters.Binary.BinaryFormatter) data into it.
On the other side or the connection (on both sides actually) you definetly should have a byte[] buffer which u will append and trim-left at runtime when data is coming.
Something like that I am using:
namespace System.Net.Sockets
{
public class TcpConnection : IDisposable
{
public event EvHandler<TcpConnection, DataArrivedEventArgs> DataArrive = delegate { };
public event EvHandler<TcpConnection> Drop = delegate { };
private const int IntSize = 4;
private const int BufferSize = 8 * 1024;
private static readonly SynchronizationContext _syncContext = SynchronizationContext.Current;
private readonly TcpClient _tcpClient;
private readonly object _droppedRoot = new object();
private bool _dropped;
private byte[] _incomingData = new byte[0];
private Nullable<int> _objectDataLength;
public TcpClient TcpClient { get { return _tcpClient; } }
public bool Dropped { get { return _dropped; } }
private void DropConnection()
{
lock (_droppedRoot)
{
if (Dropped)
return;
_dropped = true;
}
_tcpClient.Close();
_syncContext.Post(delegate { Drop(this); }, null);
}
public void SendData(PCmds pCmd) { SendDataInternal(new object[] { pCmd }); }
public void SendData(PCmds pCmd, object[] datas)
{
datas.ThrowIfNull();
SendDataInternal(new object[] { pCmd }.Append(datas));
}
private void SendDataInternal(object data)
{
if (Dropped)
return;
byte[] bytedata;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
try { bf.Serialize(ms, data); }
catch { return; }
bytedata = ms.ToArray();
}
try
{
lock (_tcpClient)
{
TcpClient.Client.BeginSend(BitConverter.GetBytes(bytedata.Length), 0, IntSize, SocketFlags.None, EndSend, null);
TcpClient.Client.BeginSend(bytedata, 0, bytedata.Length, SocketFlags.None, EndSend, null);
}
}
catch { DropConnection(); }
}
private void EndSend(IAsyncResult ar)
{
try { TcpClient.Client.EndSend(ar); }
catch { }
}
public TcpConnection(TcpClient tcpClient)
{
_tcpClient = tcpClient;
StartReceive();
}
private void StartReceive()
{
byte[] buffer = new byte[BufferSize];
try
{
_tcpClient.Client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, DataReceived, buffer);
}
catch { DropConnection(); }
}
private void DataReceived(IAsyncResult ar)
{
if (Dropped)
return;
int dataRead;
try { dataRead = TcpClient.Client.EndReceive(ar); }
catch
{
DropConnection();
return;
}
if (dataRead == 0)
{
DropConnection();
return;
}
byte[] byteData = ar.AsyncState as byte[];
_incomingData = _incomingData.Append(byteData.Take(dataRead).ToArray());
bool exitWhile = false;
while (exitWhile)
{
exitWhile = true;
if (_objectDataLength.HasValue)
{
if (_incomingData.Length >= _objectDataLength.Value)
{
object data;
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(_incomingData, 0, _objectDataLength.Value))
try { data = bf.Deserialize(ms); }
catch
{
SendData(PCmds.Disconnect);
DropConnection();
return;
}
_syncContext.Post(delegate(object T)
{
try { DataArrive(this, new DataArrivedEventArgs(T)); }
catch { DropConnection(); }
}, data);
_incomingData = _incomingData.TrimLeft(_objectDataLength.Value);
_objectDataLength = null;
exitWhile = false;
}
}
else
if (_incomingData.Length >= IntSize)
{
_objectDataLength = BitConverter.ToInt32(_incomingData.TakeLeft(IntSize), 0);
_incomingData = _incomingData.TrimLeft(IntSize);
exitWhile = false;
}
}
StartReceive();
}
public void Dispose() { DropConnection(); }
}
}
That is just an example, you should edit it for your use.
I have had luck using the socket object directly (rather than the TCP client). I create a Server object that looks something like this (I've edited some stuff such as exception handling out for brevity, but I hope that the idea comes across.)...
public class Server()
{
private Socket sock;
// You'll probably want to initialize the port and address in the
// constructor, or via accessors, but to start your server listening
// on port 8080 and on any IP address available on the machine...
private int port = 8080;
private IPAddress addr = IPAddress.Any;
// This is the method that starts the server listening.
public void Start()
{
// Create the new socket on which we'll be listening.
this.sock = new Socket(
addr.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
// Bind the socket to the address and port.
sock.Bind(new IPEndPoint(this.addr, this.port));
// Start listening.
this.sock.Listen(this.backlog);
// Set up the callback to be notified when somebody requests
// a new connection.
this.sock.BeginAccept(this.OnConnectRequest, sock);
}
// This is the method that is called when the socket recives a request
// for a new connection.
private void OnConnectRequest(IAsyncResult result)
{
// Get the socket (which should be this listener's socket) from
// the argument.
Socket sock = (Socket)result.AsyncState;
// Create a new client connection, using the primary socket to
// spawn a new socket.
Connection newConn = new Connection(sock.EndAccept(result));
// Tell the listener socket to start listening again.
sock.BeginAccept(this.OnConnectRequest, sock);
}
}
Then, I use a separate Connection class to manage the individual connection with the remote host. That looks something like this...
public class Connection()
{
private Socket sock;
// Pick whatever encoding works best for you. Just make sure the remote
// host is using the same encoding.
private Encoding encoding = Encoding.UTF8;
public Connection(Socket s)
{
this.sock = s;
// Start listening for incoming data. (If you want a multi-
// threaded service, you can start this method up in a separate
// thread.)
this.BeginReceive();
}
// Call this method to set this connection's socket up to receive data.
private void BeginReceive()
{
this.sock.BeginReceive(
this.dataRcvBuf, 0,
this.dataRcvBuf.Length,
SocketFlags.None,
new AsyncCallback(this.OnBytesReceived),
this);
}
// This is the method that is called whenever the socket receives
// incoming bytes.
protected void OnBytesReceived(IAsyncResult result)
{
// End the data receiving that the socket has done and get
// the number of bytes read.
int nBytesRec = this.sock.EndReceive(result);
// If no bytes were received, the connection is closed (at
// least as far as we're concerned).
if (nBytesRec <= 0)
{
this.sock.Close();
return;
}
// Convert the data we have to a string.
string strReceived = this.encoding.GetString(
this.dataRcvBuf, 0, nBytesRec);
// ...Now, do whatever works best with the string data.
// You could, for example, look at each character in the string
// one-at-a-time and check for characters like the "end of text"
// character ('\u0003') from a client indicating that they've finished
// sending the current message. It's totally up to you how you want
// the protocol to work.
// Whenever you decide the connection should be closed, call
// sock.Close() and don't call sock.BeginReceive() again. But as long
// as you want to keep processing incoming data...
// Set up again to get the next chunk of data.
this.sock.BeginReceive(
this.dataRcvBuf, 0,
this.dataRcvBuf.Length,
SocketFlags.None,
new AsyncCallback(this.OnBytesReceived),
this);
}
}
You can use your Connection object to send data by calling its Socket directly, like so...
this.sock.Send(this.encoding.GetBytes("Hello to you, remote host."));
As I said, I've tried to edit the code here for posting, so I apologize if there are any errors in it.
First of all, TCP does not guarantee that everything that you send will be received with the same read at the other end. It only guarantees that all bytes that you send will arrive and in the correct order.
Therefore, you will need to keep building up a buffer when reading from the stream. You will also have to know how large each message is.
The simplest ever is to use a non-typeable ASCII character to mark the end of the packet and look for it in the received data.
I've developed a dotnet library that might come in useful. I have fixed the problem of never getting all of the data if it exceeds the buffer, which many posts have discounted. Still some problems with the solution but works descently well https://github.com/Apollo013/DotNet-TCP-Communication

Reading off a socket until end of line C#?

I'm trying to write a service that listens to a TCP Socket on a given port until an end of line is recived and then based on the "line" that was received executes a command.
I've followed a basic socket programming tutorial for c# and have come up with the following code to listen to a socket:
public void StartListening()
{
_log.Debug("Creating Maing TCP Listen Socket");
_mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, _port);
_log.Debug("Binding to local IP Address");
_mainSocket.Bind(ipLocal);
_log.DebugFormat("Listening to port {0}",_port);
_mainSocket.Listen(10);
_log.Debug("Creating Asynchronous callback for client connections");
_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
public void OnClientConnect(IAsyncResult asyn)
{
try
{
_log.Debug("OnClientConnect Creating worker socket");
Socket workerSocket = _mainSocket.EndAccept(asyn);
_log.Debug("Adding worker socket to list");
_workerSockets.Add(workerSocket);
_log.Debug("Waiting For Data");
WaitForData(workerSocket);
_log.DebugFormat("Clients Connected [{0}]", _workerSockets.Count);
_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
catch (ObjectDisposedException)
{
_log.Error("OnClientConnection: Socket has been closed\n");
}
catch (SocketException se)
{
_log.Error("Socket Exception", se);
}
}
public class SocketPacket
{
private System.Net.Sockets.Socket _currentSocket;
public System.Net.Sockets.Socket CurrentSocket
{
get { return _currentSocket; }
set { _currentSocket = value; }
}
private byte[] _dataBuffer = new byte[1];
public byte[] DataBuffer
{
get { return _dataBuffer; }
set { _dataBuffer = value; }
}
}
private void WaitForData(Socket workerSocket)
{
_log.Debug("Entering WaitForData");
try
{
lock (this)
{
if (_workerCallback == null)
{
_log.Debug("Initializing worker callback to OnDataRecieved");
_workerCallback = new AsyncCallback(OnDataRecieved);
}
}
SocketPacket socketPacket = new SocketPacket();
socketPacket.CurrentSocket = workerSocket;
workerSocket.BeginReceive(socketPacket.DataBuffer, 0, socketPacket.DataBuffer.Length, SocketFlags.None, _workerCallback, socketPacket);
}
catch (SocketException se)
{
_log.Error("Socket Exception", se);
}
}
public void OnDataRecieved(IAsyncResult asyn)
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState;
try
{
int iRx = socketData.CurrentSocket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
_log.DebugFormat("Created Char array to hold incomming data. [{0}]",iRx+1);
System.Text.Decoder decoder = System.Text.Encoding.UTF8.GetDecoder();
int charLength = decoder.GetChars(socketData.DataBuffer, 0, iRx, chars, 0);
_log.DebugFormat("Read [{0}] characters",charLength);
String data = new String(chars);
_log.DebugFormat("Read in String \"{0}\"",data);
WaitForData(socketData.CurrentSocket);
}
catch (ObjectDisposedException)
{
_log.Error("OnDataReceived: Socket has been closed. Removing Socket");
_workerSockets.Remove(socketData.CurrentSocket);
}
catch (SocketException se)
{
_log.Error("SocketException:",se);
_workerSockets.Remove(socketData.CurrentSocket);
}
}
This I thought was going to be a good basis for what I wanted to do, but the code I have appended the incoming characters to a text box one by one and didn't do anything with it. Which doesn't really work for what I want to do.
My main issue is the decoupling of the OnDataReceived method from the Wait for data method. which means I'm having issues building a string (I would use a string builder but I can accept multiple connections so that doesn't really work.
Ideally I'd like to look while listening to a socket until I see and end of line character and then call a method with the resulting string as a parameter.
What's the best way to go about doing this.
Try using asynch sockets. The code below will listening to a socket, and if the new line char through telnet is recieved it will echo it back out to the incomming socket. It seems like you would just need to redirect that input to your text box.
private string _hostName;
private const int _LISTENINGPORT = 23;
private Socket _incomingSocket;
byte[] _recievedData;
//todo: do we need 1024 byte? the asynch methods read the bytes as they come
//so when 1 byte typed == 1 byte read. Unless its new line then it is two.
private const int _DATASIZE = 1024;
public ConnectionServer()
{
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
_hostName = Dns.GetHostName();
_recievedData = new byte[_DATASIZE];
_incomingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(localAddr, _LISTENINGPORT);
_incomingSocket.Bind(endPoint);
_incomingSocket.Listen(10);
}
~ConnectionServer()
{
}
public void StartListening()
{
_incomingSocket.BeginAccept(new AsyncCallback(OnAccept), _incomingSocket);
}
private void OnAccept(IAsyncResult result)
{
UserConnection connectionInfo = new UserConnection();
Socket acceptedSocket = (Socket)result.AsyncState;
connectionInfo.userSocket = acceptedSocket.EndAccept(result);
connectionInfo.messageBuffer = new byte[_DATASIZE];
//Begin acynch communication with target socket
connectionInfo.userSocket.BeginReceive(connectionInfo.messageBuffer, 0, _DATASIZE, SocketFlags.None,
new AsyncCallback(OnReceiveMessage), connectionInfo);
//reset the listnening socket to start accepting
_incomingSocket.BeginAccept(new AsyncCallback(OnAccept), result.AsyncState);
}
private void OnReceiveMessage(IAsyncResult result)
{
UserConnection connectionInfo = (UserConnection)result.AsyncState;
int bytesRead = connectionInfo.userSocket.EndReceive(result);
if (connectionInfo.messageBuffer[0] != 13 && connectionInfo.messageBuffer[1] != 10)
//ascii for newline and line feed
//todo dress this up
{
if (string.IsNullOrEmpty(connectionInfo.message))
{
connectionInfo.message = ASCIIEncoding.ASCII.GetString(connectionInfo.messageBuffer);
}
else
{
connectionInfo.message += ASCIIEncoding.ASCII.GetString(connectionInfo.messageBuffer);
}
}
else
{
connectionInfo.userSocket.Send(ASCIIEncoding.ASCII.GetBytes(connectionInfo.message), SocketFlags.None);
connectionInfo.userSocket.Send(connectionInfo.messageBuffer, SocketFlags.None);
connectionInfo.message = string.Empty;
connectionInfo.messageBuffer = new byte[_DATASIZE];
}
{
public class UserConnection
{
public Socket userSocket { get; set; }
public Byte[] messageBuffer { get; set; }
public string message { get; set; }
}
}
You seem to have several issues:
You have an asynchronous method called WaitForData. That's very confusing, as methods with the word Wait in their names generally block the currently executing thread until something happens (or, optionally, a timeout expires). This does the exact opposite. Are you intending for this to be a synchronous or asynchronous operation?
There's also no need to instantiate the Decoder object, nor do you need the char array for (it seems) anything; just call System.Text.Encoding.UTF8.GetString(socketData.DataBuffer, 0, iRx).
You also don't appear to be doing anything with lines...which is why it doesn't do anything with lines.
Your approach with using a StringBuilder is what I would do. I would add a StringBuilder to the SocketData class and call it Builder. As you capture string data, do something like this:
string[] data = System.Text.Encoding.UTF8.GetString(
socketData.DataBuffer, 0, iRx).Split(Environment.NewLine);
socketData.Builder.Append(data[0]);
for(int i = 1; i < data.Length; i++)
{
// the socketData.Builder variable now contains a single line, so do
// something with it here, like raise an event
OnLineReceived(builder.ToString());
socketData.Builder = new StringBuilder(data[i]);
}
The one caveat here is that UTF8 is a multi-byte encoding, meaning that you could potentially grab a chunk of data that cuts off mid-character. It's generally a better idea to do this sort of preprocessing on the other side of the communication, then send the data in an appropriately length-prefixed format.

Categories

Resources