Страница: 1 |
Страница: 1 |
Вопрос: Tcplistener нужна помощь
Добавлено: 26.07.09 21:08
Автор вопроса: Aleksey
Создаю tcplistener, и начинаю слушать определенный порт, при подключении клиента как лучше его обрабатывать?
Предполагаю 2 варианта:
1. Как в МСДН (в бесконечном цикле через AcceptTcpClient)
2. С использованием отдельного потока на каждое входящее подключение.
Остановился на втором варианте. Теперь вопрос в его реализации.
Делаю так:
по кнопке стартую листенер в отдельном потоке
ListenerThread = New Threading.Thread(AddressOf StartListen)
ListenerThread.IsBackground = True
ListenerThread.Start()
End Sub
и слушаю порт:
Try
Listener = New Net.Sockets.TcpListener(Net.IPAddress.Any, 4321)
Listener.Start(2)
End Sub
Тут возникает вопрос - А как отловить событие входящего соединения?
Ответы
Всего ответов: 11
Номер ответа: 1
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #1
Добавлено: 27.07.09 09:10
Именно так как в MSDN
Номер ответа: 2
Автор ответа:
Aleksey
Вопросов: 12
Ответов: 35
Профиль | | #2
Добавлено: 27.07.09 10:43
Т.е. после запуска tcplistener добавить
Dim TcpClient as TcpClient=TcpListener.AcceptTcpClient
End While
Тогда получается что пока не завершу работу с одним подключением, второе принять не смогу?
А вот как сделать так чтобы приняв подключение, обрабатывать и параллельно можно было принимать другие подключения?
Номер ответа: 3
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #3
Добавлено: 27.07.09 19:10
В общем случае код будет выглядеть примерно так:
Обрабокта клиента должна запускаться асинхронно, т.е. чтоб цикл продолжил выполняться дальше, принимая новых клиентов.
Как именно запускать обработку зависит от того что ты планируешь делать с клиентами, проще всего будет сделать это на основе ThreadPool или Thread
Номер ответа: 4
Автор ответа:
Aleksey
Вопросов: 12
Ответов: 35
Профиль | | #4
Добавлено: 28.07.09 02:27
Для обработки соединения создал отдельный класс "AcceptedTcClient" и при входящем подключении запускаю его экземпляр в отдельном потоке:
Dim NetClient As TcpClient = Listener.AcceptTcpClient
Dim cl As New AcceptedTcpClient
cl.IncomingTcpClient = NetClient
Dim ClientThread As Threading.Thread = New Threading.Thread(AddressOf cl.Run)
ClientThread.Start()
End While
Собственно сам класс:
Public IncomingTcpClient As TcpClient
Public Sub Run()
'Здесь обрабатываю установленное соединение
If IncomingTcpClient.Connected Then
Dim Stream As NetworkStream = IncomingTcpClient.GetStream
Dim WriteArray() As Byte
Try
WriteArray = System.Text.Encoding.UTF8.GetBytes("You connected to " & Dns.GetHostName.ToString & vbCrLf) 'создаем массив с приветствием
Stream.Write(WriteArray, 0, WriteArray.Length) 'пишем приветствие клиенту
Catch ex As Exception
MsgBox("Ошибка при посылке приветствия" & vbCrLf & ex.ToString)
End Try
If Stream.CanRead Then
While True
Dim ReadArray(10) As Byte
Stream.ReadTimeout = 100000 ' Ждем ввода комманды 100 секунд и отваливаемся по таймауту
Stream.Read(ReadArray, 0, ReadArray.Length)
'приняв сообщение от клиента, передаем её обработчику сообщений
WriteArray = CommandInterpreter(ReadArray, Stream)
End Sub 'Run()
'Функция для обработки поступившего сообщения
Private Function CommandInterpreter(ByVal Command() As Byte, ByVal ClientStream As NetworkStream) As Byte()
Dim ParsedMessage as String=""
ParsedMessage=System.Text.Encoding.UTF8.GetString(Command)
И вот тут возникает проблема! При преобразовании параметра command из массива байтов в строку оно как-то криво преобразовывается, например передаём слово help, соответственно в массиве байтов оно выглядело как первые четыре элемента в виде кодов символов, остальные с нулевыми значениями, после преобразования ParsedMessage выглядит как "help+ 7 нулевых символов , т.е. ParsedMessage.Length=11 а не 4 как хотелось бы
Может тогда кто подскажет как правильно конвертить?
Номер ответа: 5
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #5
Добавлено: 28.07.09 10:14
Проблема у тебя здесь.
Буфер размера 10 байт. С чего ты взял что туда будет считано 10 байт? Stream.Read читает столько сколько может, но не больше чем размер буфера. При этом возвращает кол-во считаных байт. Таким образом:
Также учти что при использовании UTF8 у тебя символы могут иметь различную длину (1-4 байта). Т.е. сообщение длиной 4 байта не обязательно будет состоять из 4 символов.
Номер ответа: 6
Автор ответа:
Aleksey
Вопросов: 12
Ответов: 35
Профиль | | #6
Добавлено: 28.07.09 16:07
Буфер размера 10 байт.
Клиент не будет посылать более 10-байт за раз, да и вообще собственно пока это мелочи
Пробовал использовать ASCII - та же история.
Так всё же, как быть с преобразованием полученной комманды, может как-то по другому её распознавать, без преобразования в строку? Пробовал сравнивать массивы, но они разной длины (напрм. массив с поступившей коммандой "help" имеет размер 10, а не 4)
Номер ответа: 7
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #7
Добавлено: 28.07.09 19:37
Ты вообще прочитал мое сообщение?
Stream.Read не изменяет размер буфера. Ты передаешь туда массив из 11 байт (че-то я описался, забыл что нумерация с 0). По сети получаешь 4 байта. В массив будут записаны эти 4 байта, начиная с 0-го. Остальные 7 байт будут забиты нулями или "мусором", если в массиве уже что-то было.
Тебе нужно узнать сколько байт считал метод Read, и работать только с этим блоком, еще раз рекомендую перечитать и запустить код который я привел.
Номер ответа: 8
Автор ответа:
Aleksey
Вопросов: 12
Ответов: 35
Профиль | | #8
Добавлено: 28.07.09 23:57
Блин, сообщение прочел, а в код не всмотрелся, теперь дошло как
Номер ответа: 9
Автор ответа:
Aleksey
Вопросов: 12
Ответов: 35
Профиль | | #9
Добавлено: 31.07.09 01:32
Теперь возникли очередные грабли
Когда отключается клиент, как определить это? А то на данный момент получается что клиент отвалился, а попытка чтения осуществляется (в бесконечном цикле), что и приводит к возникновению ошибки чтения из потока (IOException)
Можно конечно поместить попытку чтения в блок try и обрабатывать исключение, но может есть и более правильный способ?
Номер ответа: 10
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #10
Добавлено: 01.08.09 22:42
Посмотри TcpClient.Active, TcpClient.Connected
А вообще конечно нужно обработку ошибок ставить
Номер ответа: 11
Автор ответа:
Aleksey
Вопросов: 12
Ответов: 35
Профиль | | #11
Добавлено: 02.08.09 20:14
Active - такого не нашел, возможно перепутал с available, а connected в этот момент показывает true
Пока сделал через обработку ошибки:
но не уверен что это правильно