Ошибка TCP-сокета С# — 10060

У меня есть служба Windows, выступающая в качестве сервера. И я запускаю одну форму приложения Windows Form Localhost в качестве клиента. Обе программы используют подключение к сокету TCP для отправки/получения данных. Сервер слушает порт 8030. Программа работает нормально.

НО, когда я расширил клиентскую программу для связи через определенный порт, скажем, 9030. При подключении к серверу она генерирует следующее исключение.

Попытка подключения не удалась, так как подключенная сторона не ответила должным образом через некоторое время, или не удалось установить соединение, поскольку подключенный хост не ответил 192.168.10.198:8030

Любое предложение будет высоко оценено.

Спасибо, Мадхусмита.

Для справки

Код программы сервера

public partial class TestService : ServiceBase
{
    Socket serverSocket = null;
    public Timer timer1;
    IPEndPoint ipEndPoint;

    public TestService()
    {
        InitializeComponent();
        timer1 = new Timer(10000);
        timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
    }

protected override void OnStart(string[] args)
    {
        EventLog.WriteEntry("Application", "Service started", EventLogEntryType.Information, 555);
        try
        {

            ipEndPoint = new IPEndPoint(IPAddress.Any, 8030);
            //Defines the kind of socket we want :TCP
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
            //Bind the socket to the local end point(associate the socket to local end point)
            serverSocket.Bind(ipEndPoint);
            //listen for incoming connection attempt
            // Start listening, only allow 10 connection to queue at the same time
            serverSocket.Listen(10);
            timer1.Start();
        }
        catch (SocketException ex)
        {
            EventLog.WriteEntry("Application",  ex.ErrorCode + "-" +ex.Message, EventLogEntryType.Error, 555);
        }
        catch (Exception ex)
        {
            EventLog.WriteEntry("Application", ex.Message, EventLogEntryType.Error, 555);
        }
    }

    void timer1_Elapsed(object sender, ElapsedEventArgs e)
    {
        try
        {

            // The program is suspended while waiting for an incoming connection.
            // This is a synchronous TCP application
            Socket handler = serverSocket.Accept();              
            byte[] fileDetails = new byte[1500];

            //Recieve the file details
            handler.Receive(fileDetails);              
            int fileNameLength = BitConverter.ToInt32(fileDetails, 0);
            string fileName = Encoding.ASCII.GetString(fileDetails, 4, fileNameLength);
            int fileLength = BitConverter.ToInt32(fileDetails, 4 + fileNameLength);  

            FileStream fs = new FileStream(@"C:\Demo\" + fileName, FileMode.Append, FileAccess.Write);
            int byteRead = 0;

            while (byteRead < fileLength)
            {
                byte[] data = new Byte[1500];
                //Recieve teh data and write to the file
                int r = handler.Receive(data);
                fs.Write(data, 0, r);
                byteRead += r;
            }

            fs.Close();

            EventLog.WriteEntry("Application", "File saved successfully", EventLogEntryType.SuccessAudit, 555);               
            EndPoint endPoint = (EndPoint)ipEndPoint;
            handler.Send(Encoding.ASCII.GetBytes("Done"));
            handler.Close();
        }
        catch (SocketException ex)
        {
            EventLog.WriteEntry("Application", ex.Message, EventLogEntryType.Error, 555);
        }
        catch (IOException ex)
        {
            EventLog.WriteEntry("Application", ex.Message, EventLogEntryType.Error, 555);
        }
        catch (Exception ex)
        {
            EventLog.WriteEntry("Application", ex.Message, EventLogEntryType.Error, 555);

        }
    }


    protected override void OnStop()
    {
        timer1.Stop();
    }

    protected override void OnPause()
    {
        timer1.Stop();
    }

    protected override void OnContinue()
    {
        timer1.Start();

    }
    protected override void OnShutdown()
    {
        timer1.Stop();
    }
}

Код клиентской программы

public partial class Form1 : Form
{
    Socket socketClient;
    IPEndPoint remoteEndPoint;
    public Form1()
    {
        InitializeComponent();

    }

    private void buttonX1_Click(object sender, EventArgs e)
    {
        try
        {
            //Code to connect to server by by specifing the IP and port of the server on 
            //which the server application is hosted
            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //socketClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress,(int)1);

            //IP address of the machine where the server program is hosted
            IPAddress remoteIPAddress = IPAddress.Parse(txtXIPAddress.Text.Trim());

            //Specify the specific port no thart the server listens to accept the data
            int port = int.Parse(txtXPort.Text.Trim());
            remoteEndPoint = new IPEndPoint(remoteIPAddress, port);

            **//This two line causing the exception**
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9030);
            socketClient.Bind(endPoint);

            //Establish the connection to server
            socketClient.Connect(remoteEndPoint);

            MessageBox.Show("Connection established. Please select a  file to send.");
        }
        catch (SocketException ex)
        {
            MessageBox.Show(ex.ErrorCode.ToString() + "-" + ex.Message);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    private void btnXBrowse_Click(object sender, EventArgs e)
    {
        if (socketClient != null)
        {
            openFileDialog1.ShowDialog();
        }
        else
        {
            MessageBox.Show("Please connect to the server first");
        }

    }

    private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
    {

        txtXFile.Text = openFileDialog1.FileName;
    }

    private void btnXTransfer_Click(object sender, EventArgs e)
    {
        //Check if the socket is connected to the remote host 
        //otherwise prompt user to get connected to the server first
        if (socketClient != null && socketClient.Connected)
        {
            //If any file is selected then only proceed with transfer
            if (!openFileDialog1.FileName.Equals(string.Empty))
            {
                FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read);
                try
                {
                    //Get the filename
                    string filename = Path.GetFileName(openFileDialog1.FileName);

                    //Covert the file name in form of byte
                    byte[] fileNameByte = Encoding.ASCII.GetBytes(filename);

                    //4- to store the filename length(as int - 4bytes)
                    //8- to stote the file content length(as long take 8 bytes)
                    int totalLength = 4 + fileNameByte.Length + 8;

                    //Clientdata[] reprents the data to sent to the server 
                    //which represent the file details
                    byte[] clientData = new byte[totalLength];
                    byte[] fileNameLength = BitConverter.GetBytes(fileNameByte.Length);
                    byte[] fileContentLength = BitConverter.GetBytes(fs.Length);

                    //Copy all the data ClientData array
                    fileNameLength.CopyTo(clientData, 0);
                    fileNameByte.CopyTo(clientData, 4);
                    fileContentLength.CopyTo(clientData, 4 + fileNameByte.Length);

                    //Send the data to server
                    socketClient.Send(clientData);

                    int byteRead = 0;
                    int bytesToRead = (int)fs.Length;

                    while (bytesToRead > 0)
                    {
                        byte[] data = new Byte[1500];
                        byteRead = bytesToRead > 1500 ? 1500 : bytesToRead;
                        int n = fs.Read(data, 0, byteRead);

                        //Send the data to server
                        socketClient.Send(data);
                        bytesToRead -= n;
                    }

                    //Code block to get the success message from server
                    byte[] successmessage = new byte[4];
                    int msg = socketClient.Receive(successmessage);

                    if (Encoding.ASCII.GetString(successmessage).Equals("Done"))
                    {
                        MessageBox.Show("transfered the file successfully");
                        txtXFile.Text = string.Empty;
                        openFileDialog1.FileName = string.Empty;
                    }

                }

                catch (SocketException ex)
                {
                    MessageBox.Show(ex.ErrorCode + "-" + ex.Message);
                }
                catch (IOException ex)
                {
                    MessageBox.Show(ex.Message);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                finally
                {
                    fs.Close();
                    if (socketClient != null && socketClient.Connected)
                    {
                        socketClient.Shutdown(SocketShutdown.Both);
                        socketClient.Close(); ;
                    }
                }
            }
            else
            {
                MessageBox.Show("Please select afile to transfer.");
            }
        }
        else
        {
            MessageBox.Show("Please connect to the host.");
        }
    }
}

person Madhusmita    schedule 20.10.2011    source источник
comment
один любопытный вопрос, зачем привязывать клиент сокета к определенному порту??   -  person Mubashir Khan    schedule 20.10.2011
comment
В соответствии с требованиями моего проекта программа клиентских сокетов будет установлена ​​в разных больницах. В БД есть таблица, которая сопоставляет идентификаторы больниц с определенным портом. Поэтому, когда я получаю данные от клиента, я проверяю порт входящего запроса и узнаю, из какой больницы я получаю данные.   -  person Madhusmita    schedule 20.10.2011
comment
попробуйте это для целей тестирования IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0); socketClient.Bind (конечная точка);   -  person Mubashir Khan    schedule 20.10.2011
comment
Я думаю, указав порт как 0, клиент будет использовать случайный порт для связи. Но мне нужно, чтобы клиент общался с использованием определенного порта.   -  person Madhusmita    schedule 20.10.2011
comment
Для справки, определение личности клиента, по какому порту он отправляет, вероятно, является одним из самых уродливых способов, которые я видел. Если происходит какой-либо NAT или проксирование и т. д., вы облажались. Было бы намного, намного, намного лучше, если бы вы могли отправлять некоторую информацию об идентификаторе / аутентификации по соединению, а не молиться, чтобы клиент не был вредоносным.   -  person cHao    schedule 20.10.2011
comment
упс, опечатка, я имел в виду IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 9030);   -  person Mubashir Khan    schedule 20.10.2011


Ответы (1)


Примечание. Вам не нужно привязывать локальный конец клиентского сокета — платформа и/или ОС автоматически привязываются к эфемерному порту. На самом деле, если вы привяжете сокет к 127.0.0.1, предполагая, что соединение не вызывает исключение о недоступных хостах, произойдет одно из двух (я не уверен, что именно):

  • Клиент попытается подключиться к серверу, но, поскольку локальный конец привязан к IP-адресу петлевого интерфейса, он будет отправлять по нему, а не по сети. -или-
  • Клиент правильно направит пакет через сетевую карту, и сервер получит его. Сервер отвечает клиенту: «Хорошо, давайте настроим это соединение»… но поскольку клиент сказал, что его адрес 127.0.0.1, именно здесь сервер будет пытаться подключиться. Используя собственный петлевой интерфейс, потому что туда направляется 127.0.0.1.

В любом случае пакеты теряются в одном из петлевых интерфейсов машин, и клиент никогда не увидит ответа.

Если вам необходимо выполнить привязку в клиенте, выберите свой реальный IP-адрес или используйте IPAddress.Any, например:

var endPoint = new IPEndPoint(IPAddress.Any, 9030);

Это будет привязано к данному порту, но по-прежнему позволит ОС выбирать IP-адрес. А вот 127.0.0.1 скорее всего не подойдет.

person cHao    schedule 20.10.2011