Link to home
Start Free TrialLog in
Avatar of Tom Knowlton
Tom KnowltonFlag for United States of America

asked on

Server pushing data to client - slowly

I have a server program (windows form) sending data to a client via TCP/IP.

I am reading an entife file into an ArrayList first.......then stepping through the ArrayList line by line and pushing the data to the client.


It seems to me that the entire process should take no longer than 5 or 10 seconds.  Instead it is taking minutes.

I cannot for the life of me figure-out where the delay is.  My intent is to push the data through as fast as possible.


The data file is 1.2 MB in size.

The timer that sends the data fires every 1 milliseconds.


Here is the Server side code:


using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Collections;

namespace DefaultNamespace
{
      /// <summary>
      /// Description of SocketServer.      
      /// </summary>
      public class SocketServer : System.Windows.Forms.Form
      {
            private System.Windows.Forms.Label label3;
            private System.Windows.Forms.Label label2;
            private System.Windows.Forms.TextBox textBoxPort;
            private System.Windows.Forms.TextBox textBoxMsg;
            private System.Windows.Forms.Button buttonStopListen;
            private System.Windows.Forms.Label label1;
            private System.Windows.Forms.TextBox textBoxIP;
            private System.Windows.Forms.Button buttonStartListen;
            private System.Windows.Forms.Button buttonClose;

            //Tom
            private System.IO.StreamReader filereader = null;
            private ArrayList linesFromFile = new ArrayList();
            private int curLine=0;

            
            
            const int MAX_CLIENTS = 10;
            
            public AsyncCallback pfnWorkerCallBack ;
            private  Socket m_mainSocket;
            private  Socket [] m_workerSocket = new Socket[10];
            private System.Windows.Forms.Timer timer1;
            private System.ComponentModel.IContainer components;
            private System.Windows.Forms.ListBox listBox1;
            private System.Windows.Forms.Label label6;
            private System.Windows.Forms.TextBox textBox1;
            private System.Windows.Forms.TextBox textBox2;
            private int m_clientCount = 0;
            
            public SocketServer()
            {
                  //
                  // The InitializeComponent() call is required for Windows Forms designer support.
                  //
                  InitializeComponent();
                  
                  // Display the local IP address on the GUI
                  textBoxIP.Text = GetIP();
            }
            
            [STAThread]
            public static void Main(string[] args)
            {
                  Application.Run(new SocketServer());
            }
            
            #region Windows Forms Designer generated code
            /// <summary>
            /// This method is required for Windows Forms designer support.
            /// Do not change the method contents inside the source code editor. The Forms designer might
            /// not be able to load this method if it was changed manually.
            /// </summary>
            private void InitializeComponent() {
                  this.components = new System.ComponentModel.Container();
                  this.buttonClose = new System.Windows.Forms.Button();
                  this.buttonStartListen = new System.Windows.Forms.Button();
                  this.textBoxIP = new System.Windows.Forms.TextBox();
                  this.label1 = new System.Windows.Forms.Label();
                  this.buttonStopListen = new System.Windows.Forms.Button();
                  this.textBoxMsg = new System.Windows.Forms.TextBox();
                  this.textBoxPort = new System.Windows.Forms.TextBox();
                  this.label2 = new System.Windows.Forms.Label();
                  this.label3 = new System.Windows.Forms.Label();
                  this.timer1 = new System.Windows.Forms.Timer(this.components);
                  this.listBox1 = new System.Windows.Forms.ListBox();
                  this.label6 = new System.Windows.Forms.Label();
                  this.textBox1 = new System.Windows.Forms.TextBox();
                  this.textBox2 = new System.Windows.Forms.TextBox();
                  this.SuspendLayout();
                  //
                  // buttonClose
                  //
                  this.buttonClose.Location = new System.Drawing.Point(152, 152);
                  this.buttonClose.Name = "buttonClose";
                  this.buttonClose.Size = new System.Drawing.Size(88, 24);
                  this.buttonClose.TabIndex = 11;
                  this.buttonClose.Text = "Close";
                  this.buttonClose.Click += new System.EventHandler(this.ButtonCloseClick);
                  //
                  // buttonStartListen
                  //
                  this.buttonStartListen.BackColor = System.Drawing.Color.Blue;
                  this.buttonStartListen.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
                  this.buttonStartListen.ForeColor = System.Drawing.Color.Yellow;
                  this.buttonStartListen.Location = new System.Drawing.Point(152, 56);
                  this.buttonStartListen.Name = "buttonStartListen";
                  this.buttonStartListen.Size = new System.Drawing.Size(88, 40);
                  this.buttonStartListen.TabIndex = 4;
                  this.buttonStartListen.Text = "Start Listening";
                  this.buttonStartListen.Click += new System.EventHandler(this.ButtonStartListenClick);
                  //
                  // textBoxIP
                  //
                  this.textBoxIP.Location = new System.Drawing.Point(88, 16);
                  this.textBoxIP.Name = "textBoxIP";
                  this.textBoxIP.Size = new System.Drawing.Size(120, 20);
                  this.textBoxIP.TabIndex = 12;
                  this.textBoxIP.Text = "";
                  //
                  // label1
                  //
                  this.label1.Location = new System.Drawing.Point(16, 40);
                  this.label1.Name = "label1";
                  this.label1.Size = new System.Drawing.Size(48, 16);
                  this.label1.TabIndex = 1;
                  this.label1.Text = "Port";
                  //
                  // buttonStopListen
                  //
                  this.buttonStopListen.BackColor = System.Drawing.Color.Red;
                  this.buttonStopListen.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
                  this.buttonStopListen.ForeColor = System.Drawing.Color.Yellow;
                  this.buttonStopListen.Location = new System.Drawing.Point(152, 104);
                  this.buttonStopListen.Name = "buttonStopListen";
                  this.buttonStopListen.Size = new System.Drawing.Size(88, 40);
                  this.buttonStopListen.TabIndex = 5;
                  this.buttonStopListen.Text = "Stop Listening";
                  this.buttonStopListen.Click += new System.EventHandler(this.ButtonStopListenClick);
                  //
                  // textBoxMsg
                  //
                  this.textBoxMsg.BackColor = System.Drawing.SystemColors.Control;
                  this.textBoxMsg.BorderStyle = System.Windows.Forms.BorderStyle.None;
                  this.textBoxMsg.ForeColor = System.Drawing.SystemColors.HotTrack;
                  this.textBoxMsg.Location = new System.Drawing.Point(120, 240);
                  this.textBoxMsg.Name = "textBoxMsg";
                  this.textBoxMsg.ReadOnly = true;
                  this.textBoxMsg.Size = new System.Drawing.Size(192, 13);
                  this.textBoxMsg.TabIndex = 14;
                  this.textBoxMsg.Text = "None";
                  //
                  // textBoxPort
                  //
                  this.textBoxPort.Location = new System.Drawing.Point(88, 40);
                  this.textBoxPort.Name = "textBoxPort";
                  this.textBoxPort.Size = new System.Drawing.Size(40, 20);
                  this.textBoxPort.TabIndex = 0;
                  this.textBoxPort.Text = "8000";
                  //
                  // label2
                  //
                  this.label2.Location = new System.Drawing.Point(16, 16);
                  this.label2.Name = "label2";
                  this.label2.Size = new System.Drawing.Size(56, 16);
                  this.label2.TabIndex = 2;
                  this.label2.Text = "Server IP";
                  //
                  // label3
                  //
                  this.label3.Location = new System.Drawing.Point(0, 240);
                  this.label3.Name = "label3";
                  this.label3.Size = new System.Drawing.Size(112, 16);
                  this.label3.TabIndex = 13;
                  this.label3.Text = "Status Message:";
                  //
                  // timer1
                  //
                  this.timer1.Interval = 1;
                  this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
                  //
                  // listBox1
                  //
                  this.listBox1.AllowDrop = true;
                  this.listBox1.Location = new System.Drawing.Point(16, 72);
                  this.listBox1.Name = "listBox1";
                  this.listBox1.Size = new System.Drawing.Size(120, 95);
                  this.listBox1.TabIndex = 15;
                  this.listBox1.DragDrop += new System.Windows.Forms.DragEventHandler(this.listBox1_DragDrop);
                  this.listBox1.DragEnter += new System.Windows.Forms.DragEventHandler(this.listBox1_DragEnter);
                  //
                  // label6
                  //
                  this.label6.Location = new System.Drawing.Point(24, 176);
                  this.label6.Name = "label6";
                  this.label6.TabIndex = 16;
                  this.label6.Text = "label6";
                  //
                  // textBox1
                  //
                  this.textBox1.Location = new System.Drawing.Point(8, 272);
                  this.textBox1.Name = "textBox1";
                  this.textBox1.Size = new System.Drawing.Size(200, 20);
                  this.textBox1.TabIndex = 17;
                  this.textBox1.Text = "textBox1";
                  //
                  // textBox2
                  //
                  this.textBox2.Location = new System.Drawing.Point(8, 304);
                  this.textBox2.Name = "textBox2";
                  this.textBox2.Size = new System.Drawing.Size(304, 20);
                  this.textBox2.TabIndex = 18;
                  this.textBox2.Text = "textBox2";
                  //
                  // SocketServer
                  //
                  this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
                  this.ClientSize = new System.Drawing.Size(328, 341);
                  this.Controls.Add(this.textBox2);
                  this.Controls.Add(this.textBox1);
                  this.Controls.Add(this.textBoxMsg);
                  this.Controls.Add(this.textBoxIP);
                  this.Controls.Add(this.textBoxPort);
                  this.Controls.Add(this.label6);
                  this.Controls.Add(this.listBox1);
                  this.Controls.Add(this.label3);
                  this.Controls.Add(this.buttonClose);
                  this.Controls.Add(this.buttonStopListen);
                  this.Controls.Add(this.buttonStartListen);
                  this.Controls.Add(this.label2);
                  this.Controls.Add(this.label1);
                  this.Name = "SocketServer";
                  this.Text = "SocketServer";
                  this.Load += new System.EventHandler(this.SocketServer_Load);
                  this.ResumeLayout(false);

            }
            #endregion
            void ButtonStartListenClick(object sender, System.EventArgs e)
            {
                  this.timer1.Enabled = true;

                  try
                  {
                        // Check the port value
                        if(textBoxPort.Text == ""){
                              MessageBox.Show("Please enter a Port Number");
                              return;
                        }
                        string portStr = textBoxPort.Text;
                        int port = System.Convert.ToInt32(portStr);
                        // Create the listening socket...
                        m_mainSocket = new Socket(AddressFamily.InterNetwork,
                                                  SocketType.Stream,
                                                  ProtocolType.Tcp);
                        IPEndPoint ipLocal = new IPEndPoint (IPAddress.Any, port);
                        // Bind to local IP Address...
                        m_mainSocket.Bind( ipLocal );
                        // Start listening...
                        m_mainSocket.Listen (4);
                        // Create the call back for any client connections...
                        m_mainSocket.BeginAccept(new AsyncCallback (OnClientConnect), null);
                        
                        UpdateControls(true);

                        
                        
                  }
                  catch(SocketException se)
                  {
                        MessageBox.Show ( se.Message );
                  }

            }
            private void UpdateControls( bool listening )
            {
                  buttonStartListen.Enabled       = !listening;
                  buttonStopListen.Enabled       = listening;
            }      
            // This is the call back function, which will be invoked when a client is connected
            public void OnClientConnect(IAsyncResult asyn)
            {
                  try
                  {
                        // Here we complete/end the BeginAccept() asynchronous call
                        // by calling EndAccept() - which returns the reference to
                        // a new Socket object
                        m_workerSocket[m_clientCount] = m_mainSocket.EndAccept (asyn);
                        // Let the worker Socket do the further processing for the
                        // just connected client
                        WaitForData(m_workerSocket[m_clientCount]);
                        // Now increment the client count
                        ++m_clientCount;
                        // Display this client connection as a status message on the GUI      
                        String str = String.Format("Client # {0} connected", m_clientCount);
                        textBoxMsg.Text = str;
                        
                        // Since the main Socket is now free, it can go back and wait for
                        // other clients who are attempting to connect
                        m_mainSocket.BeginAccept(new AsyncCallback ( OnClientConnect ),null);

                        
                        
                  }
                  catch(ObjectDisposedException)
                  {
                        System.Diagnostics.Debugger.Log(0,"1","\n OnClientConnection: Socket has been closed\n");
                  }
                  catch(SocketException se)
                  {
                        MessageBox.Show ( se.Message );
                  }
                  
            }
            public class SocketPacket
            {
                  public System.Net.Sockets.Socket m_currentSocket;
                  public byte[] dataBuffer = new byte[1];
            }
            // Start waiting for data from the client
            public void WaitForData(System.Net.Sockets.Socket soc)
            {
                  try
                  {
                        if  ( pfnWorkerCallBack == null ){            
                              // Specify the call back function which is to be
                              // invoked when there is any write activity by the
                              // connected client
                              pfnWorkerCallBack = new AsyncCallback (OnDataReceived);
                        }
                        SocketPacket theSocPkt = new SocketPacket ();
                        theSocPkt.m_currentSocket       = soc;
                        // Start receiving any data written by the connected client
                        // asynchronously
                        soc .BeginReceive (theSocPkt.dataBuffer, 0,
                                           theSocPkt.dataBuffer.Length,
                                           SocketFlags.None,
                                           pfnWorkerCallBack,
                                           theSocPkt);
                  }
                  catch(SocketException se)
                  {
                        MessageBox.Show (se.Message );
                  }

            }
            // This the call back function which will be invoked when the socket
            // detects any client writing of data on the stream
            public  void OnDataReceived(IAsyncResult asyn)
            {
                  try
                  {
                        SocketPacket socketData = (SocketPacket)asyn.AsyncState ;

                        int iRx  = 0 ;
                        // Complete the BeginReceive() asynchronous call by EndReceive() method
                        // which will return the number of characters written to the stream
                        // by the client
                        iRx = socketData.m_currentSocket.EndReceive (asyn);
                        char[] chars = new char[iRx +  1];
                        System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
                        int charLen = d.GetChars(socketData.dataBuffer,
                                                 0, iRx, chars, 0);
                        System.String szData = new System.String(chars);
                        //richTextBoxReceivedMsg.AppendText(szData);
      
                        // Continue the waiting for data on the Socket
                        WaitForData( socketData.m_currentSocket );
                  }
                  catch (ObjectDisposedException )
                  {
                        System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket has been closed\n");
                  }
                  catch(SocketException se)
                  {
                        MessageBox.Show (se.Message );
                  }
            }
            void ButtonSendMsgClick(object sender, System.EventArgs e)
            {
                  SendData();

//                  try
//                  {
//                        Object objData = richTextBoxSendMsg.Text;
//                        byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString ());
//                        for(int i = 0; i < m_clientCount; i++){
//                              if(m_workerSocket[i] != null){
//                                    if(m_workerSocket[i].Connected){
//                                          m_workerSocket[i].Send (byData);
//                                    }
//                              }
//                        }
//                        
//                  }
//                  catch(SocketException se)
//                  {
//                        MessageBox.Show (se.Message );
//                  }
            }

            void SendData()
            {
                  string tempStringToSend="";
                  int tempCurLine=0;

                  try
                  {
                        //Object objData = richTextBoxSendMsg.Text;

                        tempCurLine = curLine;
                        tempStringToSend = (string)linesFromFile[tempCurLine];
                        
                        Object objData = (object)tempStringToSend;
                        
                        //Show what line we are on
                        this.textBox1.Text = tempCurLine.ToString();

                        //Show what we are sending
                        this.textBox2.Text = tempStringToSend;

                        byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString ());
                        for(int i = 0; i < m_clientCount; i++)
                        {
                              if(m_workerSocket[i] != null)
                              {
                                    if(m_workerSocket[i].Connected)
                                    {
                                          m_workerSocket[i].Send (byData);
                                    }
                              }
                        }
                        
                  }
                  catch(SocketException se)
                  {
                        MessageBox.Show (se.Message );
                  }
            }
            
            void ButtonStopListenClick(object sender, System.EventArgs e)
            {
                  CloseSockets();                  
                  UpdateControls(false);
            }
      
         String GetIP()
         {         
                     String strHostName = Dns.GetHostName();
            
                     // Find host by name
                     IPHostEntry iphostentry = Dns.GetHostByName(strHostName);
            
                     // Grab the first IP addresses
                     String IPStr = "";
                     foreach(IPAddress ipaddress in iphostentry.AddressList){
                    IPStr = ipaddress.ToString();
                           return IPStr;
                     }
                     return IPStr;
         }
         void ButtonCloseClick(object sender, System.EventArgs e)
         {
                     CloseSockets();
                     Close();
         }
         void CloseSockets()
         {
                     if(m_mainSocket != null){
                           m_mainSocket.Close();
                     }
                  for(int i = 0; i < m_clientCount; i++){
                        if(m_workerSocket[i] != null){
                              m_workerSocket[i].Close();
                              m_workerSocket[i] = null;
                        }
                  }      
         }


            private void timer1_Tick(object sender, System.EventArgs e)
            {
                  SendData();
                  curLine++;
                  if(curLine > linesFromFile.Count -1)
                  {
                        curLine = 0;
                  }
            }


            private void listBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
            {
                  string[] files = (string[])e.Data.GetData("FileDrop", false);
                  foreach (string s in files)
                  {
                        //just filename
                        listBox1.Items.Add(s.Substring(1 + s.LastIndexOf(@"\")));
                        //or fullpathname
                        //     listBox1.Items.Add(s);
                        // If you want to add the text in the drag file, please read it line by line and add to the list box here.

                        filereader = new System.IO.StreamReader(s);

            //            linesFromFile.Add("BEGIN");

                        do
                        {
                              linesFromFile.Add(filereader.ReadLine());
                        }
                        while(filereader.Peek() != -1);

                        this.label6.Text = "DONE";
                  }
            }


            private void listBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
            {
                  if (e.Data.GetDataPresent(DataFormats.FileDrop))
                        e.Effect = DragDropEffects.All;
                  else
                        e.Effect = DragDropEffects.None;

            }

            private void SocketServer_Load(object sender, System.EventArgs e)
            {
            
            }
      }
}
Avatar of cookre
cookre
Flag of United States of America image

Since you leave the timer enabled during the timer interrupt handling, what's the likelihood that SendData will complete without being itself interrupted after just 1ms?

See hat happens if you disable the timer as the first thing in Timer1_Tick(), then re-enable just before leavingL

          private void timer1_Tick(object sender, System.EventArgs e)
          {
               timer1.Enabled=false;
               SendData();
               curLine++;
               if(curLine > linesFromFile.Count -1)
               {
                    curLine = 0;
               }
          timer1.Enabled=true;
          }


Avatar of Tom Knowlton

ASKER

cookre:

I think your suggestion helps some...but it is still pretty slow!!!!!!!
You mean we'll have to really LOOK at the code?
Uh, OK.
You mean we'll have to really LOOK at the code?
Uh, OK.

===============

Yeah....I apologize for that.  :)
I should mention that the read-in of the file INTO the ArrayList is very very FAST...like under 1 second.

It is when I start to push the data out via TCP IP that I am getting the slow-down.

Unless your lines are close to the size of a packet, you're doing a gazillion sends.  

When you expect to do large transfers, the common way is to fill a packet with as much as you can and reassemble the data on the recieving end.  Note that this means you have to include sequence info in each packet so the re-assembler isn't fooled by out of sequence packets.

Let's say your lines average 100 bytes each.  This means you're doing ten times more sends than if you sent 10 lines per packet.
>>>>Unless your lines are close to the size of a packet, you're doing a gazillion sends.


Yes....the ArrayList contains 100,000 lines plus, and I am sending one line at a time.


>>>>When you expect to do large transfers, the common way is to fill a packet with as much as you can and reassemble the data on the recieving end.  Note that this means you have to include sequence info in each packet so the re-assembler isn't fooled by out of sequence packets.

So how should my server code change?
ASKER CERTIFIED SOLUTION
Avatar of cookre
cookre
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial