.NET 4.x Технология клиент-сервер. Классы клиента и сервера. Обсуждение - Visual Basic .NET
Формулировка задачи:
В данном теме выкладываю свои классы клиента и сервера, а так же простеньких примеров реализованных на этих классах. Жду конструктивной критики, идей, предложений по улучшению, оптимизации и прочего.
Сообщение в разработке. Примеры будут чуть позже.
Так же прошу поправлять меня, если комментарии в коде не соответствуют реальной действительности. Комментировал то как я это понимаю.
P.S. с орфографией тоже туговато, так что исправляем
Листинг программы
- Imports System.Net.Sockets
- Public Class Class_Server
- Public Delegate Sub StatusInvoker(ByVal t As String) ' делегат для синхронизации при выводе сообщений
- Private port As Integer = 13000 ' порт сервера на котором он работает
- Private server_name As String ' название сервера. Например: Game, Authorization server . Просто для удобства
- Private flag As Byte ' в текущий версии не используется. В будущем планируется клиентов с другим флагом сразу отключать, что бы только "правильные" клиенты могли подключаться к серверу.
- Private server_Listener As TcpListener ' Сам TcpListener который и прослушивает нужный порт
- Private clientsList As New Hashtable ' Список клиентов. (Уникальный индификатор ID,сам класс клиента)
- Public Event OnRead(ByVal _client As handleClinet, ByVal _data As String) ' Событие вызываемое при получении данных от клиентов
- Public Event Connect(ByVal _client As handleClinet) ' Событие вызываемое при подключении клиента
- Public Event Disconnect(ByVal _client As handleClinet, ByVal _reson As String) ' Событие вызываемое при отключении клиента
- Public Event messege(ByVal text As String) ' событие вызываемое, когда нужно передать информацию из класса
- Public Sub New(ByVal _Port As Integer, ByVal _Name As String, ByVal _Flag As Byte) ' инициализация класса. Порт, название, флаг
- port = _Port
- server_name = _Name
- flag = _Flag
- End Sub
- Public Sub start() ' Запуск сервера.
- Dim server_Thread As Threading.Thread = New Threading.Thread(AddressOf startServ)
- server_Thread.Start() ' Запуск отдельного потока на прослушивание порта и подключений к серверу
- End Sub
- Public Sub stop_server() ' Процедура для закрытия сервера.
- Dim Item As DictionaryEntry
- Dim list As Hashtable = clientsList
- For Each Item In list ' Перебор всех клиентов в списке
- CType(Item.Value, handleClinet).closeClient() ' Закрываем каждого клиента, что бы поток клиента завершился.
- Next
- server_Listener.Stop() ' Остановка прослушивания порта
- End Sub
- Public ReadOnly Property User_List() As Hashtable ' Возращаем список клиентов в виде хэш таблицы.
- Get
- Return clientsList
- End Get
- End Property
- Private Sub Client_OnRead(ByVal client As handleClinet, ByVal data As String) ' Процедура, вызываемая при получении сервером данных от клиента
- RaiseEvent OnRead(client, data) ' вызываем событие сервера, что клиент прислал данные
- End Sub
- Private Sub Client_Disconnect(ByVal client As handleClinet, ByVal reson As String) ' Процедура, вызываемая при отключении клиента
- clientsList.Remove(client.ID) ' удаляем клиента из списка клиентов
- RaiseEvent Disconnect(client, reson) ' вызываем событие сервера, что отключился клиент
- End Sub
- Public Sub Send_user(ByVal client As handleClinet, ByVal data As String) ' Процедура отправки данных нужному клиенту
- Dim tcp As TcpClient = client.TCP() ' получаем TcpClient нужный для получения потока записи
- Dim stream As NetworkStream = tcp.GetStream ' получение потока записи
- Dim mess() As Byte = System.Text.Encoding.UTF8.GetBytes(data) ' преобразование сообщения в байты для потока
- stream.Write(mess, 0, mess.Length) ' отсылка данных в виде байт
- stream.Flush() ' честно не знаю, что это делает. Работает и с этим и без, но в большинстве примеров есть, поэтому оставил.
- End Sub
- Public Sub Send_all(ByVal data As String) ' Процедура посылки сообщения всем клиентам
- Dim Item As DictionaryEntry
- Dim list As Hashtable = clientsList
- For Each Item In list ' Перебор всех клиентов и рассылка через Send_user
- Send_user(CType(Item.Value, handleClinet), data)
- Next
- End Sub
- Private Sub startServ() ' процедура служащая для прослушивания порта и подключении клиентов
- Dim client As TcpClient
- Dim count As Integer ' Кол-во подключений
- Try
- server_Listener = New TcpListener(port)
- server_Listener.Start() ' Начинаем прослушивать порт
- msg("=========Сервер " & Me.server_name & " запущен...=========")
- While True ' Бесконечный цикл, что бы клиенты могли подключаться всегда
- count += 1 ' Новое подключение, значит счетчик +1
- client = server_Listener.AcceptTcpClient() ' Ждем подключения. Когда клиент подключается, запоминаем его в client
- Dim temp_client As New handleClinet(client, count) ' Создаем новый класс клиента и передаем ему подключившегося клиента и его номер подключения
- temp_client.startClient(Me) ' Запускаем клиента и прослушивание входящих сообщений. Ссылку на класс сервера передаем, что бы клиент мог добавить своё событие на Client_OnRead
- clientsList.Add(temp_client.ID, temp_client) ' Добавляем клиента в список клиентов
- RaiseEvent Connect(temp_client) ' Вызываем событие, что клиент подключился
- End While
- Catch ex As Exception
- msg("=========Ошибка сервера " & Me.server_name & ". Причина: " & ex.Message) ' Сообщаем об ошибке
- End Try
- ' Так как сюда попасть можно, только после ошибки, значит сервер остановлен. Сообщаем об этом.
- msg("=========Сервер " & Me.server_name & " остановлен!=========")
- End Sub
- Public Sub msg(ByVal t As String) ' Процедура отправки сообщения
- Try
- RaiseEvent messege(t) ' Вызываем событие о новом сообщении
- Catch ex As Exception
- MsgBox(ex.Message, , "Msg Сервера")
- End Try
- End Sub
- Public Class handleClinet ' Класс клиента в сервере. Нужен для индификации и базовых дейсвий с клиентом
- Public Event OnRead(ByVal _client As handleClinet, ByVal _data As String) ' Событие, что текущий клиент получил данные
- Public Event Disconnect(ByVal _client As handleClinet, ByVal _reson As String) ' Событие при отключении текущего клиента
- Private mgID As Guid = Guid.NewGuid ' Получаем уникальный индификатор клиента для хэш таблицы списка клиентов
- Private clientSocket As TcpClient ' Сокет клиента
- Private stream As NetworkStream ' Поток данных клиента
- Private clNo As String ' Номер клиента
- ' Private serv As Class_Server
- Private myIP As String ' Храним тут ип этого клиента
- Public Sub New(ByVal inClientSocket As TcpClient, ByVal count As Integer) ' Инициализация клиента
- Me.clientSocket = inClientSocket
- Me.stream = clientSocket.GetStream()
- Me.clNo = count
- End Sub
- Public ReadOnly Property IP() As String ' Получение IP
- Get
- If myIP = "" Then myIP = clientSocket.Client.RemoteEndPoint.ToString
- Return myIP
- End Get
- End Property
- Public ReadOnly Property ID() As String ' Получение ID
- Get
- Return mgID.ToString
- End Get
- End Property
- Public ReadOnly Property Number() As String ' Получение номера клиента
- Get
- Return clNo.ToString
- End Get
- End Property
- Public ReadOnly Property TCP() As TcpClient ' Получение TcpClient клиента
- Get
- Return clientSocket
- End Get
- End Property
- Public Sub closeClient() ' Процедура принудительного закрытия подключения клиента
- stream.Close()
- clientSocket.Close()
- End Sub
- Public Sub startClient(ByVal _serv As Class_Server) ' Процедура запуска клиента
- Dim client_Thread As Threading.Thread = New Threading.Thread(AddressOf doListen)
- client_Thread.Start() ' Запуск прослушивания новых данных текущим клиентом в отедьном потоке
- AddHandler Me.OnRead, AddressOf _serv.Client_OnRead ' При срабатывании события OnRead в клиенте, вызываем процедуру Client_OnRead на самом сервере
- AddHandler Me.Disconnect, AddressOf _serv.Client_Disconnect ' При срабатывании события Disconnect в клиенте, вызываем процедуру Client_Disconnect на самом сервере
- End Sub
- Private Sub doListen()
- Dim bytes(1048576) As Byte ' 1мб буфер, что бы данные не дробились.
- Dim data As String
- Dim i As Int32
- Try
- i = stream.Read(bytes, 0, bytes.Length) ' Ждем новых данных от клиентского приложения. При получении заносим данные в буфер bytes и длину данных в i
- While (i <> 0) ' Цикл бесконечный, пока длина считанных данных не окажется=0, что ознает, что клиент оключился.
- data = System.Text.Encoding.UTF8.GetString(bytes, 0, i) ' Переводим байты в текст
- RaiseEvent OnRead(Me, data) ' Вызываем событие о получении новых данных
- i = stream.Read(bytes, 0, bytes.Length) ' Ждем новых данных от клиентского приложения. При получении заносим данные в буфер bytes и длину данных в i
- End While
- closeClient() ' Так как вышли из цикла, то клиентское приложение закрыло соединение. Следовательно закрываем и мы.
- RaiseEvent Disconnect(Me, "Клиент решил отключиться от сервера.") ' Вызываем событие, что клиент отключился и передаем причину.
- Catch ex As Exception
- closeClient() ' Ошибка, значит отключаем клиента.
- RaiseEvent Disconnect(Me, "Проблема соединения: " & ex.Message) ' Вызываем событие, что клиент отключился и передаем причину.
- End Try
- End Sub
- End Class
- End Class
Листинг программы
- Imports System.Net.Sockets
- Public Class Class_client
- Public Delegate Sub StatusInvoker(ByVal t As String) ' делегат для синхронизации при выводе сообщений
- Dim client As TcpClient ' Текущий TcpClient связывающий клиента и сервер
- Dim stream As NetworkStream ' Поток данных связывающий клиента и сервер
- Dim flag As Byte ' Пока не используется. Нужен для индификации сервером "правильного" клиента
- Dim connection As Boolean = False ' Состояние подключения
- Public Event OnRead(ByVal _data As String) ' Событие, при получении данных от сервера
- Public Event Disconnected(ByVal _reson As String) ' Событие, при отключении от сервера
- Public Event messege(ByVal text As String) ' Событие, при необходимости передать сообщение из класса
- Dim s As Object
- Public Function Connect(ByVal server As String, ByVal port As Integer, ByVal _Flag As Byte) As Boolean ' Функция подключения клиента к серверу. Вернет True в случае удачи и False при ошибке.
- If connection = False Then ' Проверка не подключены ли мы уже?
- Try
- Me.client = New TcpClient(server, port)
- Me.stream = client.GetStream()
- Me.flag = _Flag
- Dim client_Thread As Threading.Thread = New Threading.Thread(AddressOf Me.doListen)
- client_Thread.Start() ' Запуск отдельного потока на прослушивание данных с сервера.
- connection = True ' Состояние=Подключен
- Return True
- Catch ex As Exception
- msg(ex.Message) ' Сообщаем об ошибке
- Return False
- End Try
- Else
- Return False ' Если уже подключены, тогда новое подключение не удалось
- End If
- End Function
- Public Sub Disconnect(Optional ByVal s As String = "") ' Процедура отключения от сервера. Возможно указать коментарий.
- If connection Then
- connection = False ' Состояние=Отключен
- stream.Close()
- client.Close()
- If s = "" Then
- RaiseEvent Disconnected("Отключен") ' Вызываем событие отключения с коментарием "по умолчанию"
- Else
- RaiseEvent Disconnected(s) ' Вызываем событие отключения с коментарием указанным при вызове текущей процедуры
- End If
- End If
- End Sub
- Public Function Send(ByVal data As String) As Boolean ' Функция отправки сообщения серверу. Вернет True, если посылка удалась или False в обратном случаее
- If connection Then
- Try
- Dim databyte() As Byte = System.Text.Encoding.UTF8.GetBytes(data) ' Создаем массив байтов для отправки из Data
- stream.Write(databyte, 0, databyte.Length) ' Отправляем наш массив байт.
- stream.Flush() ' честно не знаю, что это делает. Работает и с этим и без, но в большинстве примеров есть, поэтому оставил.
- Return True ' Говорим, что посылка удалась
- Catch ex As Exception
- msg(ex.Message) ' Сообщаем об ошибке
- Disconnect("Проблема при отправке.") ' Отключаемся
- Return False
- End Try
- Else
- Return False ' Если не подключены, то отправка не удалась.
- End If
- End Function
- Private Sub doListen() ' Процедура прослушки сообщений от сервера
- Dim bytes(1048576) As Byte ' 1мб буфер, чтобы данные не дробились.
- Dim data As String
- Dim i As Int32
- Try
- i = stream.Read(bytes, 0, bytes.Length) ' Ждем новых данных от сервера. При получении заносим данные в буфер bytes и длину данных в i
- While (i <> 0) ' Цикл бесконечный, пока длина считанных данных не окажется=0, что ознает, что соединение с сервером прекращенно.
- data = System.Text.Encoding.UTF8.GetString(bytes, 0, i) ' Переводим байты в текст
- RaiseEvent OnRead(data) ' Вызываем событие о получении новых данных
- i = stream.Read(bytes, 0, bytes.Length) ' Ждем новых данных от сервера. При получении заносим данные в буфер bytes и длину данных в i
- End While
- Disconnect() ' Так как вышли из цикла, то сервер закрыло соединение. Следовательно отключаемся.
- Catch ex As Exception
- Disconnect(ex.Message) ' Ошибка, значит отключаемся, указав причину.
- End Try
- End Sub
- Public Sub msg(ByVal t As String) ' Процедура отправки сообщения
- Try
- RaiseEvent messege(t) ' Вызываем событие о новом сообщении
- Catch ex As Exception
- MsgBox(ex.Message)
- End Try
- End Sub
- End Class
Решение задачи: «.NET 4.x Технология клиент-сервер. Классы клиента и сервера. Обсуждение»
textual
Листинг программы
- Public Sub Send_user(ByVal client As handleClinet, ByVal data As String) ' Процедура отправки данных нужному клиенту
- Dim tcp As TcpClient = client.TCP() ' получаем TcpClient нужный для получения потока записи
- Dim stream As NetworkStream = tcp.GetStream ' получение потока записи
- Dim mess() As Byte = System.Text.Encoding.UTF8.GetBytes(data) ' преобразование сообщения в байты для потока
- stream.Write(mess, 0, mess.Length) ' отсылка данных в виде байт
- stream.Flush() ' честно не знаю, что это делает. Работает и с этим и без, но в большинстве примеров есть, поэтому оставил.
- End Sub
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д