Невозможно принять TcpClient во второй раз C#

Я новичок как в C#, так и в программировании клиент-сервер. Прямо сейчас, для класса, я пытаюсь создать клиент FTP без использования каких-либо предварительно установленных библиотек FTP. Я чувствую, что проект по большей части отключен, однако я сталкиваюсь с проблемой, когда выполняю несколько вызовов, требующих использования порта данных (list, retr и т. Д.). Вот пример кода. это ломает:

writer.WriteLine(portcmd);
writer.Flush();

GetServerMessage(stream);

writer.WriteLine("list ");
writer.Flush();


tmpserver = new TcpListener(IPAddress.Any, 3128);
tmpserver.Start(); 
tmpclient = tmpserver.AcceptTcpClient();
Console.WriteLine("gothere");

if (!tmpclient.Connected)
{
    tmpserver.Start();
}

StreamReader tmpreader = new StreamReader(tmpclient.GetStream());

GetServerMessage(stream);
while (tmpreader.Peek() != -1)
{
    Console.WriteLine(tmpreader.ReadLine());
}

tmpclient.Close();
tmpserver.Stop();

GetServerMessage(stream);

Getservermessage - это метод, который берет сетевой поток и распечатывает все доступное в течение 0,5 секунды, поток - это NetworkStream для текущего подключения к FTP-серверу, а Writer - это тот же сетевой поток, заключенный в StreamReader для простоты записи ASCII. персонажи на сервер. Если вам интересно, почему я использую потоковое считывающее устройство для чтения из подключения к данным, это происходит потому, что сервер закрывает подключение после передачи данных, чтобы я мог легко получить уведомление eof. Мой метод GetServerMessage по какой-то причине сломался, когда я использовал закрытый сетевой поток.

Этот код отправляет команду порта на FTP-сервер, чтобы сообщить ему, что мне потребуется соединение для передачи данных (первые 2 строки). Затем отправляет команду списка, устанавливает соединение для передачи данных на сервер, получает необходимую информацию и затем завершает работу. передача данных (остальная часть кода).

Этот код будет выполняться без ошибок при первом запуске, но если я попробую еще раз, он зависнет в 'tmpclient = tmpserver.AcceptTcpClient();' линия. Он никогда не доходит до "полученного" печатного заявления. Я полагаю, что это потому, что я получаю клиента с той же машины на тот же порт, но я не уверен. Я попытался добавить логическое значение, чтобы убедиться, что AcceptTcpClient () запускался только один раз, но затем я получил ошибку времени выполнения, и Visual Studio сообщила мне, что, возможно, я "освободил ресурсы до того, как закончил с ними", я предсказал, что это будет проблемой, но Как я могу определить, восстанавливает ли сервер соединение после того, как он его закрыл?

В конце данного кода я останавливаю tmpserver и закрываю tmpclient. Первоначально я сделал это, потому что знал, что FTP-сервер закроет соединение, когда он закончит передачу, и думал, что это правильно. Я нахожу, что если я закомментирую эти строки, код будет выполняться несколько раз, но потоки кажутся пустыми... Я не уверен, что эта информация полезна, но я решил упомянуть об этом.

Я прошу прощения, если мне вообще неясно, но мое отсутствие знаний по предмету затрудняет формулирование моей проблемы. Если есть какая-то путаница в том, в чем проблема, я был бы рад попытаться прояснить ее.

3 ответа

Решение

Чтобы иметь возможность принять другого клиента, вы должны выполнить tmpclient = tmpserver.AcceptTcpClient(); и ожидание того, что первый клиент закончит свою работу (прежде чем принять второго клиента), может быть не очень хорошей идеей

Вот пример кода сервера, который ожидает подключения и отображает строки, отправленные каждым клиентом. Вы можете проверить это с telnet localhost 3128

Thread t = new Thread(Server);
t.IsBackground = true;
t.Start();

-

void Server()
{
    TcpListener listener = new TcpListener(IPAddress.Any, 3128);
    listener.Start();
    while (true)
    {
        var client = listener.AcceptTcpClient();
        new Thread(() =>
        {
            using (client)
            {
                var reader = new StreamReader(client.GetStream());
                var writer = new StreamWriter(client.GetStream());
                while (true)
                {
                    string line = reader.ReadLine();
                    if (line == "QUIT") break;
                    writer.WriteLine("From Thread[" + Thread.CurrentThread.ManagedThreadId + "] > " + line);
                    writer.Flush();
                }
            }
        }).Start();
    }
}

ОК, это так Чтобы сделать сервер простым способом, вам нужно скопировать код, который обрабатывает сокет клиента. Когда accept возвращается, создайте и запустите поток, передав ему tmpclient, а затем снова вернитесь к вызову accept, чтобы любой новый клиент мог подключиться. В новом порожденном клиентском потоке server<> выполните чтение и запись в переданный сокет в цикле для связи с клиентом.

Как только вы закроете свой клиентский поток tcp, вы больше не сможете читать из потока, который вы извлекли из него.

var stream = tcpClient.GetStream();
...
tcpclient.Close();
...
stream.Read .. fail

Клиент должен будет запросить другое соединение,

ИЛИ ЖЕ

Вы должны держать свои сокеты tcp-клиента открытыми.

Более сложные серверы будут сохранять некоторые метаданные (состояние) в кэше о клиенте, поэтому, когда сокеты неожиданно закрываются - и клиент быстро пытается восстановить соединение, сервер может продолжить плавную обработку.

Другие вопросы по тегам