0

I have a Server class that receives .txt file from client class.

My problem: My server only receives the first .txt file but after that the client can't send anymore, how can I convert my Server class such that the server will always will listening to new files?

Here is the server:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string rd;
        byte[] b1;
        string v;
        int m=20;//number of byts
        TcpListener list;
        TcpClient client;
        int port = 8100;//5050
        int port1 = 8100;//5055
        IPAddress localAddr = IPAddress.Parse("127.0.0.1");
        private void button1_Click(object sender, EventArgs e)//browse button
        {

            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = folderBrowserDialog1.SelectedPath;
               // while (true)

                    //try
                   // {
                        list = new TcpListener(localAddr, port1);
                        list.Start();


                        Thread incoming_connection = new Thread(ic);
                        incoming_connection.Start();
                        /*
                    }catch(Exception exc)
                    {
                        Console.Write(exc);
                        break;
                    }*/

            }
        }

        private void ic()
        {

            client = list.AcceptTcpClient();
            Stream s = client.GetStream();
            b1 = new byte[m];
            s.Read(b1,0, b1.Length);
            MessageBox.Show("pathh "+textBox1.Text);
            File.WriteAllBytes(textBox1.Text+"\\flag.txt", b1);// the left side us the name of the written file
            //list.Stop();
            //client.Close();
          //  label1.Text = "File Received......";
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            list = new TcpListener(localAddr, port);
           // TcpListener list = new TcpListener(port);
            list.Start();
            TcpClient client = list.AcceptTcpClient();
            MessageBox.Show("Client trying to connect");
            StreamReader sr = new StreamReader(client.GetStream());
            rd = sr.ReadLine();
            v = rd.Substring(rd.LastIndexOf('.') + 1);
            m = int.Parse(v);
           // list.Stop();
           // client.Close();
        }
    }

Related-1 Realted-2

Rickless
  • 1,377
  • 3
  • 17
  • 36
Error 404
  • 427
  • 5
  • 25
  • A socket represents a *stream* of data. It knows nothing of "files" or "end of file". As such, you'd need to provide some sort of envelope that carries file metadata to split out such items. Now the question is too broad. – spender Dec 11 '17 at 16:54
  • HTTP is pretty good at this sort of thing, btw. – spender Dec 11 '17 at 16:54
  • Your client code `TcpClient` executed only once, when the form is loaded. Are you sure this is the way you want it to be? Also, keep in mind that your code will accept only one client! one connection. If you want to send more files you should keep the client alive, you should move the client logic to somewhere else, other than the `form_load` event handler – Rickless Dec 11 '17 at 17:22
  • If you think I misunderstand your problem, please edit your question with more details or add comment here, explaining your problem. – Rickless Dec 11 '17 at 17:26
  • @Mahmoud that's exactly my question, I need that the server will continue to listen, can you please show me how? – Error 404 Dec 11 '17 at 17:29
  • OK, give me couple minutes please. – Rickless Dec 11 '17 at 17:29
  • I've posted my solution, tell me if it helped you or not. – Rickless Dec 11 '17 at 18:15

1 Answers1

0

First, You need someone to send text, and someone to receive text
Let's begin with the Sender, let's call it Server

public class Server
{
    //This is where the receiver connection will be stored
    public TcpClient ClientConnection { get; set; }
    public int Port { get; set; }
    public string Host { get; set; }
    public TcpListener Listener;
    public Server(int port,string host)
    {
         this.Port = port;
         this.Host = host;
    }
    public void Start()
    {
         this.Listener = new TcpListener(IPAddress.Parse(Host), Port);
         TryConnect();
    }
    public void TryConnect()
    {
         //You can use thread
         Task.Factory.StartNew(AcceptTheClientConnection, TaskCreationOptions.LongRunning);
    }
    public void AcceptTheClientConnection()
    {
        ClientConnection = this.Listener.AcceptTcpClient();
    }
    public void SendText(string text)
    {
         if (ClientConnection != null)
         {
             try
             {
                 var buffer = System.Text.Encoding.Default.GetBytes(text);
                 ClientConnection.Client.Send(buffer, SocketFlags.None);
             }
             catch(Exception e)
             {
                 ClientConnection = null;
                 TryConnect();
             }
         }
            else throw new InvalidOperationException("You must connect to client first");
    }
}

Now The Receiver is a TcpClient, this Receiver will open the connection by providing it with the Sender IP Address and the port. The Receiver will run two threads after successfully connecting to the Sender. The first thread will keep listening for new files, adding the received file buffer to the queue. The second one will process these buffers, here you can put your own logic.

public class Client
{
    public int SenderPort { get; set; }
    public byte[] Buffer { get; set; }
    public string SenderHost { get; set; }
    public TcpClient SenderConnection;
    public Queue<byte[]> ReceivedTextFiles;
    public Client(int senderPort, string senderHost)
    {
        this.SenderPort = senderPort;
        this.SenderHost = senderHost;
        ReceivedTextFiles = new Queue<byte[]>();
    }
    public Task Connect()
    {
        return Task.Factory.StartNew(() =>
        {
            SenderConnection = new TcpClient();
            SenderConnection.Connect(SenderHost, SenderPort);
            Thread t = new Thread(Recieve);
            Thread t2 = new Thread(ProcessTextFiles);
            t.Start();
            t2.Start();
        });
    }
    public void Recieve()
    {
        while (true)
        {
            Thread.Sleep(500);
            if (SenderConnection.Available > 0)
            {
                lock (Buffer)
                {
                    Buffer = new byte[SenderConnection.Available];
                    int receivedBytes = SenderConnection.Client.Receive(Buffer);
                    if (receivedBytes > 0)
                    {
                        lock (ReceivedTextFiles)
                        {
                            ReceivedTextFiles.Enqueue(Buffer);
                            Buffer = null;
                        }
                    }
                }
            }
        }
    }
    public void ProcessTextFiles()
    {
        while (true)
        {
            byte[] textFile = null;
            lock (ReceivedTextFiles)
            {
                //We have buffers to process, get one, and remove it from the queue
                if (ReceivedTextFiles.Count > 0)
                {
                    textFile = ReceivedTextFiles.Dequeue();
                }
            }
            //Process the buffer
            var textFileContent = System.Text.Encoding.Default.GetString(textFile);
            //Do whatever you want
            Thread.Sleep(1500);
        }
    }
}

This is the general idea behind sockets, and how to send and receive data in the network. Keep in mind, this solution is tailored for your purpose, which will accept only one connection. And this is not the best solution, but due to your requirement; I tried to make it as simple as possible. Also please note that you can use Threads, or Tasks It depends on the context. I will let you chose who to consume these two classes as you want. You can edit these two classes of course.

Rickless
  • 1,377
  • 3
  • 17
  • 36