Search code examples
c#socketstcptcpclienttcpserver

Trying to create a server that will receive more than 1 file, but it always stops after receiving 1 file


Im trying to create a server that will receive files from clients, right now its working but not the way i want it to. the way i wanted it to work is:
1. Start server
2. Receive file from client #1
3. Send some other file back to client #1
4. Receive another file from client #1
And so on, until the client stops the connection.
Right now the server is doing that:
1. Start server
2. Receive file from client #1
3. (Suppose to write back to the client but i haven't added it yet)
4. (At this point the client sends the 2nd file, but the server dosent get it)
This is the error i get on step 4 on the client side:

System.Net.Sockets.SocketException was unhandled
  HResult = -2147467259
  Message = was unable to make a connection because the target machine actively rejected it 192.168.1.11:5442
  Source = System
  ErrorCode = 10061
  NativeErrorCode = 10061
  StackTrace:
       at System.Net.Sockets.Socket.DoConnect (EndPoint endPointSnapshot, SocketAddress socketAddress)
       at System.Net.Sockets.Socket.Connect (EndPoint remoteEP)
       at System.Net.Sockets.TcpClient.Connect (IPEndPoint remoteEP)
       at ClientTest2.Program.Main (String [] args) in c: \ Users \ Shaked \ Documents \ Visual Studio 2012 \ Projects \ ClientTest2 \ ClientTest2 \ Program.cs: line 19
       at System.AppDomain._nExecuteAssembly (RuntimeAssembly assembly, String [] args)
       at System.AppDomain.ExecuteAssembly (String assemblyFile, Evidence assemblySecurity, String [] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly ()
       at System.Threading.ThreadHelper.ThreadStart_Context (Object state)
       at System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart ()
  InnerException:

On the server side there are no errors(no runtime errors, but i think something with the code is wrong). Here is the server code (Note: its a windows form application)

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace XO
{
    public partial class MultiPlayerLobby : Form
    {
        public MultiPlayerLobby()
        {
            InitializeComponent();
        }
        public static string LocalIPAddress()
        {
            IPHostEntry host;
            string localIP = "";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIP = ip.ToString();
                    break;
                }
            }
            return localIP;
        }
        private void StartMultiPlayerGame(string player2Name)
        {
            MessageBox.Show(player2Name); //It gets the 1st string from the file, but not the 2nd file.
            //this.Close();
        }
        public string GetIP()
        {
            string externalIP = "";
            try
            {
                externalIP = (new WebClient()).DownloadString("http://checkip.dyndns.org/");
                externalIP = (new Regex(@"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}")).Matches(externalIP)[0].ToString();
            }
            catch { return "Error getting ip adress."; }
            return externalIP;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            StartServerWorker.RunWorkerAsync();
            StartServerButton.Hide();
            LoadingGif.Size = new System.Drawing.Size(LoadingGif.Size.Width, LoadingGif.Size.Height);
            LoadingGif.BackgroundImageLayout = ImageLayout.Center;
            LoadingGif.Image = Properties.Resources.LoadingGif;
            ExitButton.Size = new System.Drawing.Size(ExitButton.Width + StartServerButton.Size.Width + 15, ExitButton.Size.Height);
        }
        private void StartServerWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            try
            {
                TcpListener tcpServer = new TcpListener(IPAddress.Parse(LocalIPAddress()), 5442);
                tcpServer.Start();
                Action serverStarted = () => StatusTextBox.AppendText("Server started");
                StatusTextBox.Invoke(serverStarted);
                TcpClient client = tcpServer.AcceptTcpClient();
                Action clientConnected = () => StatusTextBox.AppendText(Environment.NewLine + ("Client connection accepted from " + client.Client.RemoteEndPoint + "."));
                StatusTextBox.Invoke(clientConnected);
                using (StreamWriter sw = new StreamWriter(Application.StartupPath + @"File.txt"))
                {
                    byte[] buffer = new byte[1500];
                    int bytesRead = 1;
                    while (bytesRead > 0)
                    {
                        bytesRead = client.GetStream().Read(buffer, 0, 1500);
                        Action startedReadingData = () => { StatusTextBox.AppendText("started reading data from client " + client.Client.RemoteEndPoint); };
                        if (bytesRead == 0)
                        {
                            break;
                        }
                        sw.BaseStream.Write(buffer, 0, bytesRead);
                    }
                    Action readAllData = () => StatusTextBox.AppendText(Environment.NewLine + ("Read all Data from client."));
                    StatusTextBox.Invoke(readAllData);
                    sw.Close();
                }
                tcpServer.Stop();
                string player2Name;
                using (TextReader tr = new StreamReader(Application.StartupPath + @"File.txt"))
                {
                    player2Name = tr.ReadLine();
                    tr.Close();
                }
                Action finished = () => StartMultiPlayerGame(player2Name);
                StatusTextBox.Invoke(finished);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void MultiPlayerLobby_Load(object sender, EventArgs e)
        {
            BackgroundGePublicIP.RunWorkerAsync();
        }

        private void ExitButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void MultiPlayerLobby_FormClosed(object sender, FormClosedEventArgs e)
        {
            //StartServerWorker.WorkerSupportsCancellation = true;
            //StartServerWorker.CancelAsync();
            //BackgroundGePublicIP.WorkerSupportsCancellation = true;
            //BackgroundGePublicIP.CancelAsync();
        }

        private void BackgroundGePublicIP_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            string publicIP = GetIP();
            Action updateIP = () => HostIPTextBox.Text = publicIP;
            HostIPTextBox.Invoke(updateIP);
        }
    }
}

Here is the client code:

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

namespace ClientTest2
{
    class Program
    {
        static void Main(string[] args)
        {
            StreamReader sr = new StreamReader(Application.StartupPath + @"\File");
            TcpClient tcpClient = new TcpClient();
            tcpClient.Connect(new IPEndPoint(IPAddress.Parse(LocalIPAddress()), 5442));
            byte[] buffer = new byte[1500];
            long bytesSent = 0;
            while (bytesSent < sr.BaseStream.Length)
            {
                int bytesRead = sr.BaseStream.Read(buffer, 0, 1500);
                tcpClient.GetStream().Write(buffer, 0, bytesRead);
                Console.WriteLine(bytesRead + " bytes sent.");
                bytesSent += bytesRead;
            }
            sr.Close();
            tcpClient.Close();
            Console.WriteLine("finished");
            Console.ReadLine();
        }
        public static string LocalIPAddress()
        {
            IPHostEntry host;
            string localIP = "";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIP = ip.ToString();
                    break;
                }
            }
            return localIP;
        }
    }
}

(the code shows only 1 file being sent, but im starting the server and then the client, after the server received the first file i close the client and open it again so it would send the file again, but at this point the server rejects the client for some reason) I'm not very good with net sockets, so please go easy on me if i did something stupid :(


Solution

  • From what i can spot out as being erroneus is that your current code misses a while() loop in the StartServerWorker_DoWork() function.

    Currently you are just starting to listen, get file, and even close it, no wonder you don't get the second file from client.

    See this example for basic TcpListener class usage.

    On the other hand, if you are going to build something that will use a lot of TCP/IP you could take a look at some already existing solution like jgauffin.framework.