Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Server pushing data to client - slowly

Posted on 2005-05-16
8
Medium Priority
?
194 Views
Last Modified: 2008-02-01
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)
            {
            
            }
      }
}
0
Comment
Question by:Tom Knowlton
  • 4
  • 4
8 Comments
 
LVL 22

Expert Comment

by:cookre
ID: 14013498
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;
          }


0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 14013676
cookre:

I think your suggestion helps some...but it is still pretty slow!!!!!!!
0
 
LVL 22

Expert Comment

by:cookre
ID: 14014529
You mean we'll have to really LOOK at the code?
Uh, OK.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 5

Author Comment

by:Tom Knowlton
ID: 14014664
You mean we'll have to really LOOK at the code?
Uh, OK.

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

Yeah....I apologize for that.  :)
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 14014675
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.

0
 
LVL 22

Expert Comment

by:cookre
ID: 14015496
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.
0
 
LVL 5

Author Comment

by:Tom Knowlton
ID: 14015507
>>>>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?
0
 
LVL 22

Accepted Solution

by:
cookre earned 2000 total points
ID: 14023531
It looks like you don't use linesFromFile except as a place to store lines for sending. If that's the case, I'd:

1) Get rid of the timer
2) Do the sends in listBox1_DragDrop():
foreach (string s in files)
            get the fully qualified filename    
            use a BinaryReader to read the file in 1k chunks into
            for each 1k chunk, build and send a buffer of 1004 bytes, where the first 4 bytes is the chunk's sequence#



[StructLayout(LayoutKind.Explicit)]
public struct BytesAndInts
{
[FieldOffset(0)] public byte b0;
[FieldOffset(1)] public byte b1;
[FieldOffset(2)] public byte b2;
[FieldOffset(3)] public byte b3;
[FieldOffset(0)] public uint i0;
}

byte[] PktBuf = new byte(1004);
...

BytesAndInts.i0=PacketSeqNo;  // PacketSeqNo starts at 0
PktBuf[0]=BytesAndInts.b0;
PktBuf[1]=BytesAndInts.b1;
PktBuf[2]=BytesAndInts.b2;
PktBuf[3]=BytesAndInts.b3;
PktBuf[4 through 1003] gets the 1000 bytes read from the file
then send the 1004 byte PktBuf.

The receiving side gets the 1004 byte packets, extracts the sequence# from the first 4 bytes, the stores the remaining 1000 bytes to HugeByteArray[1000*SeqNo] through HugeByteArray[1000*SeqNo+999].

Once all packets have been received, HugeByteArray is written to a file with a BinaryWriter.

0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Is your data getting by on basic protection measures? In today’s climate of debilitating malware and ransomware—like WannaCry—that may not be enough. You need to establish more than basics, like a recovery plan that protects both data and endpoints.…
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Suggested Courses
Course of the Month20 days, 16 hours left to enroll

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question