intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

Multithreaded Winsock

Chia sẻ: Son Cung | Ngày: | Loại File: DOC | Số trang:8

183
lượt xem
53
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Tham khảo tài liệu 'multithreaded winsock', công nghệ thông tin, kỹ thuật lập trình phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả

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 ' Instantiate TCPClient object Client = New TcpClient() ' Attempt to connect to destination (server) computer on given port number Client.Connect(DestinationComputer, TCPIPPortNo)
  2. 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 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)
  3. 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 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
  4. ' 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 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
  5. 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 ' 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
  6. 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. 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.
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2