Main Site Documentation

Network socket software problem


#1

I’m learning how to use C# sockets and am stumped at the moment–maybe someone can show me the error of my ways. I really haven’t grasped much about sockets yet.

I’ve written two programs, a server and a client. Right now they are simple programs meant to run on the same machine in order to learn about sockets. They don’t use .NET MF sockets but use the sockets of the fullblown .NET framework. Once working, I will incorporate the client into a .NET MF app using MF/GHI sockets to run on the Panda II. The server will remain as a .NET app running .NET sockets.

The server sets up a TcpListener and waits (with its AcceptTcpClient method) for a client to request connection. The client sends some test data to be read. When connected, the server reads the data (via its NetworkStream) and writes it to a text file. This simulates data being saved on a PC that was collected by the remote Panda.

When i run the programs (i start the server first), there is a connection but no bytes are read. When i step through the server program with the debugger, everything works just as expected and bytes are read from the client and written to the text file.

Here’s the server and client code, liberally smeared with WriteLines to the console and to log files. (Please ignore other problems with logic, code is not very functional or cleaned up.) Copies of the logs follow, both when running free (showing no bytes read) and when stepping through the server program w/ the debugger (showing 33 bytes read.)

Server:


using System;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;

class PBRDataServer
{
    const int    cServerIP = 65;
    const string cPBRDataFile = "PBRData.dat";
    const int    cMaxClients = 5;
    const int    cPort = 2000;
    const int    cBufSize = 1024;
    
    public static void Main()
    {
        IPAddress    serverIP   = new IPAddress(new byte[] { 192, 168, 1, cServerIP });
        byte[]       buf        = new byte[cBufSize];
        StreamWriter txtDataOut = new StreamWriter(@ cPBRDataFile);
        TcpListener  listener   = new TcpListener(serverIP, cPort);
        TcpClient    client;
        StreamWriter log  = new StreamWriter(@ "ServerLog.txt");
        
        listener.Start();
        Console.WriteLine("Data server started, listening to port {0}", cPort);
        Console.WriteLine("Listener local end point: {0}", listener.LocalEndpoint);
        log.WriteLine("Data server started, listening to port {0}", cPort);
        log.WriteLine("Listener local end point: {0}", listener.LocalEndpoint);
        //while (true) {
            client = listener.AcceptTcpClient();  // wait here until client connects
            Console.WriteLine("Connected socket local end point: {0}", client.Client.LocalEndPoint);
            Console.WriteLine("Connected socket remote end point: {0}", client.Client.RemoteEndPoint);
            log.WriteLine("Connected socket local end point: {0}", client.Client.LocalEndPoint);
            log.WriteLine("Connected socket remote end point: {0}", client.Client.RemoteEndPoint);
            try
            {
                int count = client.Available;
                Console.WriteLine("Bytes available: {0}", count);
                log.WriteLine("Bytes available: {0}", count);
                client.GetStream().Read(buf, 0, count);
                Console.WriteLine("Data server read {0} bytes", count);
                log.WriteLine("Data server read {0} bytes", count);
                count = Encoding.UTF8.GetCharCount(buf);
                txtDataOut.WriteLine(Encoding.UTF8.GetChars(buf), 0, count);
                Console.WriteLine("Data server wrote {0} chars to file {1}", count, cPBRDataFile);
                log.WriteLine("Data server wrote {0} chars to file {1}", count, cPBRDataFile);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                log.WriteLine(e.Message);
            }
            Console.WriteLine("Data server disconnected from client {0}", client.Client.RemoteEndPoint);
            log.WriteLine("Data server disconnected from client {0}", client.Client.RemoteEndPoint);
            client.Close();
        //}
        Console.ReadLine();
        txtDataOut.Close();
        log.Close();
    }
}

Client:


using System;
using System.IO;
using System.Threading;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace TestClient_WCA
{
    public class Program
    {
        private struct DataPoint {
            public float value;
            public DateTime time;

            public DataPoint(float value, DateTime time) 
            {
                this.value = value;
                this.time = time;
            }
        }

        // constants
        const int cServerIP = 65;
        const int cClientIP = 222;
        const int cPort = 2000;

        static string label = "Test data";  // text id for this data
        static DataPoint current = new DataPoint(5.5f, DateTime.Now);  // test data
        static Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        static StreamWriter log = new StreamWriter(@ "ClientLog.txt");

        public static void Main()
        {
            IPEndPoint serverEndPoint = new IPEndPoint(new IPAddress(new byte[] { 192, 168, 1, cServerIP }), cPort);
            Console.WriteLine("Connecting to server...");
            log.WriteLine("Connecting to server...");
            socket.Connect(serverEndPoint);
            Console.WriteLine("Connected? {0}", socket.Connected);
            Console.WriteLine("Socket local end point: {0}", socket.LocalEndPoint);
            Console.WriteLine("Socket remote end point: {0}", socket.RemoteEndPoint);
            log.WriteLine("Connected? {0}", socket.Connected);
            log.WriteLine("Socket local end point: {0}", socket.LocalEndPoint);
            log.WriteLine("Socket remote end point: {0}", socket.RemoteEndPoint);

            new Thread(new ThreadStart(Write)).Start();  // start new thread to write data to network
            Console.ReadLine();
            log.Close();
        }

        // save data to file via network
        private static void Write()
        {
            byte[] bytesToSend = Encoding.UTF8.GetBytes(label + "," +
                                                        current.value.ToString() + "," +
                                                        current.time.ToString());
            Console.WriteLine("Inside new thread");
            Console.WriteLine("sending {0} bytes to {1}", bytesToSend.Length, socket.RemoteEndPoint);
            log.WriteLine("Inside new thread");
            log.WriteLine("sending {0} bytes to {1}", bytesToSend.Length, socket.RemoteEndPoint);
            try
            {
                socket.Send(bytesToSend);
            }catch (Exception e) {
                Console.WriteLine(e.Message);
                log.WriteLine(e.Message);
            }
        }
    }
}

Log files

Server Log without stepping through program:

Data server started, listening to port 2000
Listener local end point: 192.168.1.65:2000
Connected socket local end point: 192.168.1.65:2000
Connected socket remote end point: 192.168.1.65:49329
Bytes available: 0
Data server read 0 bytes
Data server wrote 1024 chars to file PBRData.dat
Data server disconnected from client 192.168.1.65:49329

Client log without stepping through program:

Connecting to server…
Connected? True
Socket local end point: 192.168.1.65:49329
Socket remote end point: 192.168.1.65:2000
Inside new thread
sending 33 bytes to 192.168.1.65:2000

Server Log with stepping through program with debugger:

Data server started, listening to port 2000
Listener local end point: 192.168.1.65:2000
Connected socket local end point: 192.168.1.65:2000
Connected socket remote end point: 192.168.1.65:49330
Bytes available: 33
Data server read 33 bytes
Data server wrote 1024 chars to file PBRData.dat
Data server disconnected from client 192.168.1.65:49330

Client log with stepping through server program with debugger:

Connecting to server…
Connected? True
Socket local end point: 192.168.1.65:49330
Socket remote end point: 192.168.1.65:2000
Inside new thread
sending 33 bytes to 192.168.1.65:2000


#2

Oh, yeah. I forgot to mention that, in order to investigate whether the client running a separate thread to do the socket work contributes to the error, i ran a test that removed the new thread and called Write() directly from Main(). There was no change in the results–the server still found no bytes to read (except when stepping through w/ debugger.)


#3

Mhhh … I can’t test code in this moment, but I suggest to try implementing socket threading on the server and not on the client. On the server, remeber to dispose socket just served.
There’s also windows firewall that create problems all the times, but in this case I don’t think. Try disabling it in any case.


#4

you are closing the socket too fast. add a thread.sleep before the close.

closing the socket stops the send operation.


#5

Good guess, Mike, but no cigar. Notice the call to client.Available() used before the call to Read() returns 0 bytes when not stepping. I tried the Thread.Sleep() anyway but no change.

dobova, I’d rather not use a thread on the server because i want to model my app which will use threads on the clients to send data to the server so they can get back to work collecting data. I plan to keep the server simple with synchronous sockets as all it does is read and write (to the same file or DB) anyway and any asynchronous sockets would just end up waiting for each other to read and write. Why do you think adding asynchronous sockets on the server (would use the asynchronous methods built into .NET) would help?


#6

Mike, your guess was too good. I went back and moved the Sleep() from just before the client.Close() to just after the call to client.Available() and the problem went away. Adding the Sleep() before the call to Available() doesn’t help. Wonder why…? Anyway, on to bigger and better things. Thanks, Mike.


#7

Correction–the Sleep() is required BEFORE the call to client.Available(), after the call to listener.AcceptTcpClient(). That makes a bit more sense. Looks like 20 milliseconds is as short a wait as will work with my setup.


#8

Why are you calling client.Available? There will always be a delay between the establishment of the connection and the reception of the first data bytes.

Typically, after a server receives a connection, it just issues a read.

You should not be using sleeps to make socket programming work.


#9

The Read() call needs the number of bytes to read so i get it with Available(). Suggestions?

"You should not be using sleeps to make socket programming work."
Couldn’t agree more.


#10

Allocate a 1600 byte buffer and do a read. The return from the read will tell you how many bytes were actually read.

Socket reads can return with less than the number of bytes you specified in the read. They are not like serial ports which will block until the number of bytes you request in the read is satisfied.

With sockets you should make no assumptions as to how many bytes you will get with a read. You just specify the max you will accept, and process what you are given. Of course, you should say “Thank You” after the read. ;D


#11

Thanks for the socket facts, Mike. I was wondering about just such details, but afraid to ask. I’ll read bufSize bytes and use the return count…after calling client.ThankYou().


#12

Hi Matt5, Mike has explained and solved correctly.
I don’t use TcpClient class and normally I use directly .net sockets on the server side, but in this case you miss the GetStream(), so you need Receive() and Send(). I never get problems of closing socket and miss Receive() data … that’s strange. The Receive and Send are blocking until ReadTimeout/SendTimeout is reached (if set).
In any case the use of threading is dependent of what is your implementation and there’s not a general guide. I see you need very few data sent to server, so it’s unnecessary, but if you plan to have many clients connecting then you need to think about it.


#13

Thanks, dobova. Yeah, now that i got passed the very simple stuff, i’m starting to think about the best way to connect multiple clients to the server and realizing this is not a simple question. i will need to build a system that handles about 100 different types of data updates, but with lots of time between updates of each type (10 sec to 10 min) so i’m trying to figure out if this will be done by closing and reopening connections/sockets, keeping the connections open and using different ports, using a single or reduced number of ports and using a header id for the data, etc. If anyone knows any good discussions of these questions please direct me.


#14

if you are running on a Panda then you only have at most four sockets available, so you can not just leave idle connections open.

With a server, you will need one socket to listen for call, so that leaves two or three available for user sessions.

you might want to consider using udp instead of tcp. With udp you only need on socket.


#15

Interesting. 4 sockets available on a Panda? I was under the impression that sockets were software and unlimited. Then i heard Windows XP was limited to 10 sockets so they must be associated w/ the OS or even firmware or hardware? Is there doc on this for Panda? My server will be running on a PC with the full .NET and Windows 7. Is there a socket limit there? Sockets remain a mystery to me.


#16

This is because the networking is not built in Panda (USBizi) but controlled by external chip (Wiznet W5100).

http://www.wiznet.co.kr/Sub_Modules/en/product/Product_Detail.asp?cate1=5&cate2=7&cate3=26&pid=1011

This is true for devices that have more power and TCP/IP stack built in (e.g. EMX/Cobra). However there is always a limit unless you have unlimited resources :wink:


#17

It is set to 128 sockets on larger devices, higher values and you will be wasting memory. In my opinion, 128 sockets is considered unlimited for embedded devices. This is not a server :slight_smile:


#18

Thanks for the doc link for Wiznet. So the downside of sockets, i.e., resources used, is only memory? Or is there something more precious like some kind of connection resource? So i’ve been working w/ a Panda and FEZ Connect Wiznet chip which may be a bit limiting (4 for a unit whose sole purpose is network seems low.) If a Cobra has a limit of 128 sockets that might be a better choice plus it appears to have 5V pins which i’m finding would be nice, as well as network connection and USB onboard. Anyway, some thinking to do about how best to connect data streams.


#19

For socket programming the EMX based devices (Cobra and Spider) FEZ devices are better choices.

The Panda has less than 60KB of memory available for program use and the EMX devices have about 10+MB(Not exact numbers).

If you can afford a Cobra then don’t spend much time thinking about it. Life will be easier and/or more fun.

And then there is the Spider… Even easier and more fun. :smiley:


#20

Thanks for the advice, Mike. Yes, it looks like a Cobra or Spider are along the lines of what i need. It might be possible for me to keep sockets open but i would be up against the 128 limit for EMX-based machines. But I’m unsure if Sockets use more than just memory (10MB+ would certainly have room for 128 sockets.) Do you know if the use of multiple sockets involves more resources than the memory to allocate the socket objects, i.e., what are the drawbacks to keeping multiple sockets open? I’m trying to understand the choice between keeping sockets open and closing sockets and re-connecting for sending data updates from client (e.g. Cobra) to server (PC running full .NET) every once in a while (time span varying, depending on data type, between every 10 seconds to 10 minutes.) The amount of data sent each time will be minimal, probably less than 256 bytes. Any thoughts? Also, links to any good discussions on different designs of multiple client-server structure is appreciated. I’m less concerned about asynchronous vs. synchronous than how to best handle multiple connections.