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