Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - .NET

Страница: 1 |

 

  Вопрос: Tcplistener нужна помощь Добавлено: 26.07.09 21:08  

Автор вопроса:   Aleksey
Создаю tcplistener, и начинаю слушать определенный порт, при подключении клиента как лучше его обрабатывать?
Предполагаю 2 варианта:
1. Как в МСДН (в бесконечном цикле через AcceptTcpClient)
2. С использованием отдельного потока на каждое входящее подключение.

Остановился на втором варианте. Теперь вопрос в его реализации.
Делаю так:
по кнопке стартую листенер в отдельном потоке
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ListenerThread = New Threading.Thread(AddressOf StartListen)
        ListenerThread.IsBackground = True
        ListenerThread.Start()
End Sub

и слушаю порт:
Private Sub StartListen()

        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 добавить
While true
   Dim TcpClient as TcpClient=TcpListener.AcceptTcpClient
End While


Тогда получается что пока не завершу работу с одним подключением, второе принять не смогу?
А вот как сделать так чтобы приняв подключение, обрабатывать и параллельно можно было принимать другие подключения?

Ответить

Номер ответа: 3
Автор ответа:
 Artyom



Разработчик

Вопросов: 130
Ответов: 6602
 Профиль | | #3 Добавлено: 27.07.09 19:10
В общем случае код будет выглядеть примерно так:

  1. While true
  2.    Dim TcpClient as TcpClient=TcpListener.AcceptTcpClient
  3.    ' Запустить обработку клиента каким-либо образом
  4. End While


Обрабокта клиента должна запускаться асинхронно, т.е. чтоб цикл продолжил выполняться дальше, принимая новых клиентов.

Как именно запускать обработку зависит от того что ты планируешь делать с клиентами, проще всего будет сделать это на основе ThreadPool или Thread

Ответить

Номер ответа: 4
Автор ответа:
  Aleksey



Вопросов: 12
Ответов: 35
 Профиль | | #4 Добавлено: 28.07.09 02:27
Для обработки соединения создал отдельный класс "AcceptedTcClient" и при входящем подключении запускаю его экземпляр в отдельном потоке:
While True 'в цикле принимаем входящие подключения
      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 Class AcceptedTcpClient
    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
  1.     Dim ReadArray(10) As Byte
  2.     Stream.ReadTimeout = 100000 ' Ждем ввода комманды 100 секунд и отваливаемся по таймауту
  3.     Stream.Read(ReadArray, 0, ReadArray.Length)

Проблема у тебя здесь.

Буфер размера 10 байт. С чего ты взял что туда будет считано 10 байт? Stream.Read читает столько сколько может, но не больше чем размер буфера. При этом возвращает кол-во считаных байт. Таким образом:

  1. Dim CommandLength = Stream.Read(ReadArray, 0, ReadArray.Length)
  2. Dim Command = System.Text.Encoding.UTF8.GetString(ReadArray, 0, CommandLength)



Также учти что при использовании UTF8 у тебя символы могут иметь различную длину (1-4 байта). Т.е. сообщение длиной 4 байта не обязательно будет состоять из 4 символов.

Ответить

Номер ответа: 6
Автор ответа:
  Aleksey



Вопросов: 12
Ответов: 35
 Профиль | | #6 Добавлено: 28.07.09 16:07
  1. Dim ReadArray(10) As Byte

Проблема у тебя здесь.
Буфер размера 10 байт.

Клиент не будет посылать более 10-байт за раз, да и вообще собственно пока это мелочи

Также учти что при использовании UTF8 у тебя символы могут иметь различную длину (1-4 байта). Т.е. сообщение длиной 4 байта не обязательно будет состоять из 4 символов.

Пробовал использовать 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)
  1. Public Class AcceptedTcpClient
  2. ...
  3. While True
  4.       Dim ReadArray(10) As Byte
  5.       Stream.ReadTimeout = 100000 ' Ждем ввода комманды 100 секунд и отваливаемся по таймауту
  6.       Stream.Read(ReadArray, 0, ReadArray.Length)
  7. End While
  8. ...
  9.  
  10. End Class


Можно конечно поместить попытку чтения в блок 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
Пока сделал через обработку ошибки:
  1. Try
  2.       ReadedByteCount = Stream.Read(ReadArray, 0, ReadArray.Length)
  3.       Catch ex As Exception
  4.       If Not (TypeOf ex Is System.IO.IOException) Then
  5.         MsgBox("Ошибка при считывании данных от клиента:" & vbCrLf & ex.ToString)
  6.       End If
  7.  
  8.       Stream.Close()
  9.       IncomingTcpClient.Close()
  10.       Exit While
  11. End Try


но не уверен что это правильно

Ответить

Страница: 1 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам