views:

257

answers:

3

I am a newbie on socket programming. 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. E.g. 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? Thanks.

+1  A: 

First of all, TCP do 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 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 typable ascii character to mark the end of the packet and look for it in the recieved data.

jgauffin
thanks for your reply.I will try to read bytes in buffer ...In my question also i wonder is that good way listening incoming data with while(true)..
dankyy1
A: 

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.

Stephen Cleary
+1  A: 

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.

Pat Daburu
Hi thnx for reply..i also have 2 applications to connect 3rd party tcp server..I think one application to send command to 3rd party server and other application(as windows service) will just read incoming bytes..In this statue when i send data on 1st application with an other TcpClient object data is sent but when i read data over with 2nd application tcpclient object incoming data not changes..in this statue do I have to generate all read and write methods in a windows service and client applications should connect with remoting??more than one client can connect to service..as web application
dankyy1
I usually expend a thread to create each connection. To do that, in the Connection constructor, instead of calling BeginReceive() directly, do something like this: Thread t = new Thread(new ThreadStart(this.BeginReceive)); t.Start(); Using an approach like this, many clients can connect simultaneously. Have I understood your question correctly? You mentioned "remoting", but I'm not sure if you are referring to .Net Remoting specifically, or if you just mean "connecting from a remote client".
Pat Daburu
hi my application schema will connect to a 3rd party tcp server..I have two main tasks.one is sending command(this task can be accomplished with any internal client application in our network) and other task is listening incoming data this can be done with a centralized windows service application.So my question command sender client apps of our network should connect to our windows service app. via remoting to send commands or the client applications should connect to 3rd party tcp server with own tcpclient object to send command directly?thnx
dankyy1
Sorry for the delay (I haven't yet figured out how to get email notifications when comments are added.) From your description, it does sound as though you could use remoting (or another Windows-centric technology like WCF) to send messages from your client applications to your Windows service, then have your Windows service relay those messages using the socket connection. Or you could have the client applications connect directly, removing the need for the intermediate Windows service.
Pat Daburu