Multithreaded Winsock

Chia sẻ: Danh Ngoc | Ngày: | Loại File: PDF | Số trang:9

0
67
lượt xem
13
download

Multithreaded Winsock

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Multithreaded Winsock Vb6 cho ta Winsock Control để giúp một program VB6 nói chuyện với một program khác trên mạng TCP/IP. Ta có thể dùng Winsock Control trong một program để làm Winsock Server hay Winsock Client. Sự khác biệt nầy rất nhỏ, mặc dầu ta phải lưu ý để phân biệt sự khác nhau của hai trường hợp. Giả sử ta dùng Winsock Control làm Server trong một VB6 program để chạy trên một computer và dùng Winsock Control làm Client trong một VB6 program để chạy trên một computer khác trên mạng TCP/IP. Ðể cho hai programs nói chuyện...

Chủ đề:
Lưu

Nội dung Text: Multithreaded Winsock

  1. Multithreaded Winsock Vb6 cho ta Winsock Control để giúp một program VB6 nói chuyện với một program khác trên mạng TCP/IP. Ta có thể dùng Winsock Control trong một program để làm Winsock Server hay Winsock Client. Sự khác biệt nầy rất nhỏ, mặc dầu ta phải lưu ý để phân biệt sự khác nhau của hai trường hợp. Giả sử ta dùng Winsock Control làm Server trong một VB6 program để chạy trên một computer và dùng Winsock Control làm Client trong một VB6 program để chạy trên một computer khác trên mạng TCP/IP. Ðể cho hai programs nói chuyện (communicate) trước hết ta cần phải connect (nối) chúng lại với nhau. Ta cho Winsock Server Listen (lắng nghe) qua một LocalPort (một cổng có mang một con số, thí dụ như 9123). Kế đó ta cho Winsock Client Connect (móc nối) qua LocalPort đó ở địa chỉ TCP của Computer nơi ta chạy Winsock Server program. Sở dỉ ta cần phải nói rõ LocalPort số mấy là vì Server Computer có thể Listen qua nhiều LocalPorts cùng một lúc để nhiều Clients có thể Connect đến cùng một Computer TCP address. (Nếu bạn còn mới đối với TCP/IP hãy đọc bài Căn bản TCP/IP ) Class ServerWinsock và Class ClientWinsock Trong .NET, Winsock được thay thế bằng TcpListener và TcpClient của System.Net.Sockets. Để dùng chúng ta chỉ cần Project | Add Reference.. cái System.dll và thêm câu: Imports System.Net.Sockets ' for TcpClient and TcpServer ở đầu phần code. Khi instantiate một TcpListener object, ta cho nó một PortNo để nó lắng nghe qua cổng đó như sau: Dim oListener As TcpListener ' Variable for TcpListener ' Instantiate a TcpListener on given PortNo oListener = New TcpListener(PortNo) oListener.Start() ' Start the TcpListener Về phía Client, ta gọi method Connect của TcpClient với tên của destination/server computer (hay TCP address của computer ấy) và cái cổng trên destination/server computer. Ta code như sau: Dim Client As TcpClient ' Variable for the Client TCP socket
  2. ' Instantiate TCPClient object Client = New TcpClient() ' Attempt to connect to destination (server) computer on given port number Client.Connect(DestinationComputer, TCPIPPortNo) Bên TcpListener sẽ dùng một Socket để Accept (nhận) cái Request (thỉnh cầu) của TcpClient: ' Accept request from the TcpClient Dim oSocket As Socket oSocket = oListener.AcceptSocket Khi TcpListener AcceptSocket rồi thì hai bên TcpClient và TcpListener có thể gởi thông điệp qua lại cho đến khi một bên terminates (stop). Dưới đây là hình minh họa sự móc nối và gởi thông điệp từ Client (máy SAIGON) qua Server (máy SADEC). Từ Server ta cũng có thể gởi thông điệp qua Client cùng một cách như vậy. Một khi connection đã đứt đoạn, không dễ cho ta nối lại. Trên nguyên tắc, hai bên phải đóng socket rồi tìm cách lắng nghe/móc nối trở lại. .NET cho ta một giải pháp đơn giản và thanh tao, đó là dùng thread, một dạng process nhẹ ký. Ở cùng một cổng, mỗi khi nhận được Request-to-connect từ một TcpClient, ta instantiate một Socket chạy trong một thread riêng để phục vụ TcpClient ấy. Khi TcpClient disconnects thì ta cũng đóng socket nầy. Bên phía TcpClient, mỗi lần cần gởi một thông điệp ta instantiate một TcpClient mới, và sau khi gởi xong ta disconnect nó ngay. Cách dùng thread rất đơn giản. Muốn một Sub chạy riêng trong một thread ta
  3. chỉ cần instantiate một thread với AddressOf của Sub ấy, rồi khởi động thread ấy như sau: ' create a thread to handle this Client Request Dim oThread As Thread oThread = New Thread(AddressOf ProcessRequest) oThread.Start() ' Run Sub ProcessRequest Để dùng Thread ta chỉ cần thêm câu: Imports System.Threading ' for Thread ở đầu phần code. Trong dự án nầy, TcpListener được gói trong class ServerWinsock và TcpClient được gói trong class ClientWinsock. Chính bên trong class ServerWinsock ta dùng multithread để phục vụ nhiều TcpClient qua cùng một cổng TCPPortNo duy nhất. Class ClientWinsock chỉ gởi thông điệp và class ServerWinsock chỉ nhận thông điệp. Khi ServerWinsock nhận một thông điệp nó sẽ Raise một Event để program chủ của nó xử lý thông điệp. Thông điệp được gởi đi lại dưới dạng một array of bytes. Do đó muốn gởi một Text String ta phải cho biết Encode của Text string lúc bấy giờ là UTF8, Unicode hay ASCII, và đổi nó ra array of bytes như sau: Dim Buffer() As Byte ' used for outgoing message ' Convert UFT8 message to an array of bytes before sending Buffer = System.Text.Encoding.UTF8.GetBytes(mMessage.ToCharArray) ' Send out the buffer Client.GetStream().Write(Buffer, 0, Buffer.Length) Về phía đầu ServerWinsock, khi nhận được array of bytes thì phải đổi ra Text string trở lại như sau: ' Convert the array of bytes (i.e. the buffer) to UTF8 text string RecvMessage = System.Text.Encoding.UTF8.GetString(Buffer) ' Raise an event to return the message to the program that owns this ServerWinsock RaiseEvent OnMessage(RecvMessage) Trong thí dụ nầy ta dùng UTF8 để gởi Unicode. Nếu dữ kiện chỉ là ASCII thì có thể dùng encoding ASCII cho hiệu lực hơn vì mỗi ASCII character chỉ cần một byte: Buffer = System.Text.Encoding.ASCII.GetBytes(mMessage.ToCharArray) ' Chuẩn bị Buffer để gởi đi RecvMessage = System.Text.Encoding.ASCII.GetString(Buffer) ' Đởi lại thành ASCII text string khi nhận Thật ra để gởi Unicode ta cũng có thể dùng encoding Unicode, tức là UTF16 LittleEndian. (Nếu bạn còn mới đối với Unicode encoding hãy đọc bài Dùng
  4. Unicode chữ Việt trong .NET). Dưới đây là mã nguồn của hai classes ClientWinsock và ServerWinsock: Imports System.Threading ' for threads Imports System.Net.Sockets ' for TcpClient and TcpServer ' This module contains two classes: ClientWinsock and ServerWinsock Public Class ClientWinsock ' This object is created to connect to a TCPServer and to send a single Unicode message Private ClientThread As Thread ' used to run the main Sub StartClient of Client Private TCPIPPortNo As Integer ' TCPIP port number on destination computer Private DestinationComputer As String ' name or IP address of destination computer Private mMessage As String ' Unicode message to be sent Public Sub New( ByVal Destination As String, ByVal Message As String) ' Split the given Message into Destination computer and TCPIP port number Dim pos As Integer ' Locate the character ";" in the Message string pos = Destination.IndexOf(";") If pos > 0 Then ' the part before ";" is the name or IP address of destination computer DestinationComputer = Destination.Substring(0, pos) TCPIPPortNo = CInt(Destination.Substring(pos + 1)) ' convert string to integer Else ' character ";" does not exist, that means only TCPIP Port number is given for Localhost DestinationComputer = "Localhost" ' Destination computer is Localhost TCPIPPortNo = CInt(Destination) ' convert string to integer End If mMessage = Message ' assign outgoing message to local string variable 'Create a Thread object for Sub StartClient ClientThread = New Thread(AddressOf StartClient) 'Starting the thread invokes the ThreadStart delegate ' i.e. run Sub StartClient in its own thread ClientThread.Start() End Sub Protected Sub StartClient() ' This is the main code in ClientWinsock. It's run in its own thread Dim Client As TcpClient ' Variable for the Client TCP socket Dim Buffer() As Byte ' used for outgoing message Try ' Instantiate TCPClient object
  5. Client = New TcpClient() ' Attempt to connect to destination (server) computer on given port number Client.Connect(DestinationComputer, TCPIPPortNo) ' Convert UFT8 message to an array of bytes before sending Buffer = System.Text.Encoding.UTF8.GetBytes(mMessage.ToCharArray) ' Send out the buffer Client.GetStream().Write(Buffer, 0, Buffer.Length) Client.Close() ' Close the TcpClient Catch e As Exception ' Write to Console the message that cannot be sent Console.WriteLine("Can 't send:" & mMessage) Finally ClientThread.Abort() ' Abort thread End Try End Sub End Class Public Class ServerWinsock ' This object is created to serve many TCPClients and to receive Unicode messages ' A thread is created to serve each TCPClient Const MaxThread As Integer = 500 ' Maximum number of threads that ServerWinsock can handle Private oListener As TcpListener ' Variable for TcpListener Private bStopListener As Boolean ' Flag indicating that user wants to dispose this ServerWinsock Private ActiveThreads As Integer ' Number of active threads, i.e. threads that are serving TCPClients ' Event that returns the incoming message Public Event OnMessage( ByVal IncomingMessage As String) Public Sub New( ByVal PortNo As Integer) ' Instantiate a TcpListener on given PortNo oListener = New TcpListener(PortNo) oListener.Start() ' Start the TcpListener ' Create a thread for Sub AcceptConnection Dim ServerThread As Thread ServerThread = New Thread(AddressOf AcceptConnection) ServerThread.Start() ' Run Sub AcceptConnection like a light weight child process End Sub Protected Sub ProcessRequest() Dim Buffer(5000) As Byte ' used to receive incoming message from TcpClient Dim bytes As Integer ' Actual number of bytes read Dim RecvMessage As String ' UTF8 text string of the buffer (array of bytes) ' Use oThread to reference the thread of this Sub Dim oThread As Thread oThread = Thread.CurrentThread() ' Accept request from the TcpClient Dim oSocket As Socket oSocket = oListener.AcceptSocket
  6. ' Keep looping until user wants to stop While Not bStopListener If oSocket.Available > 0 Then ' A message has arrived from TcpClient ' read the incoming message into a buffer bytes = oSocket.Receive(Buffer, Buffer.Length, 0) SyncLock oThread ' Lock oThread ' Convert the array of bytes (i.e. the buffer) to UTF8 text string RecvMessage = System.Text.Encoding.UTF8.GetString(Buffer) ' Raise an event to return the message to the program that owns this ServerWinsock RaiseEvent OnMessage(RecvMessage) End SyncLock ' unlock oThread Exit While End If ' get out of while loop if TcpClient has disconnected If Not oSocket.Connected Then Exit While End While oSocket.Close() ' Close the TcpServer socket SyncLock oThread ' Lock oThread ActiveThreads -= 1 ' Decrement number of Active Threads End SyncLock ' unlock oThread End Sub Private Sub AcceptConnection() 'This is the main Sub of ServerWinsock ' Keep looping until user wants to stop Do While Not bStopListener Thread.Sleep(100) ' Sleep 100 msec. If oListener.Pending() Then ' received a request for connection from a TCPClient If ActiveThreads
  7. Để thử ServerWinsock và ClientWinsock, một TestBed Form được thiết kế để lăn- xê một form cho mỗi computer mà ta muốn đặt một ServerWinsock trên ấy. Ta phải nói rõ computer tên gì (hay cho TCP address của nó cũng được) và TCPPortNo, tức là con số của cổng mà nó lắng nghe. Khi khởi động, chương trình thử cho hiển thị hai TCPIPTestForms để bạn có thể thử ngay bằng cách click nút Send Bây giờ nếu bạn click nút Add Station trên TestBed form, con số TCP Port sẽ được thêm vào listbox Active Servers và một TCPIPTestForm mới sẽ được hiển thị. Click nút Send trên form mới nầy, bạn sẽ thấy message được gởi đến hai TCPIPTestForms có sẵn như sau:
  8. Bạn có thể tải về mã nguồn của chương trình nầy kể cả hai classes ClientWinsock và ServerWinsock. Trong Zip file có chứa 2 projects: TCPQueue và clsWinsock. Nếu có gặp trở ngại về việc reference thì load clsWinsock và compile trước để dùng clsWinsock.dll trong bin folder làm reference cho project TCPQueue. Sau khi load TCPQueue, bạn hãy remove clsWinsock từ References của nó rồi dùng Menu Command Project |Add Reference để refernce library clsWinsock.dll vừa mới compile. Nếu bao giờ IDE than phiền về Licence bạn chỉ cần delete file licences.licx trong Project Folder.
Đồng bộ tài khoản