I. Giới thiệu về lập trình mạng
I.3. Server phục vụ nhiều clients
Ở cỏc vớ dụ trờn chỳng ta đó thấy được sự dể dàng trong việc tạo một socket kết nối cũng như việc thao tỏc trờn cỏc dũng tin StreamNetwork giống như chỳng ta đang thao tỏc trờn cỏc dũng tin vào ra bỡnh thường khỏc. Phần tiếp theo đõy chỳng ta sẽ xem xét việc tạo ra một server cho phộp cựng lỳc nhận nhiều kết nối. Và cõu trả lời cho vấn đề này là multithreading mà chỳng ta đó xột trong phần trước. Trong cỏc ngụn ngữ khụng hỗ trợ trực tiếp multithreading thỡ mọi việc trở nờn rất phức tạp. Ở trong phần III chúng ta đó thấy sự đơn giản của multithreading. Bởi vỡ tiến trỡnh trong C# được quản lý một cỏch hợp lý nờn việc tạo ra một server để bắt tay với nhiều client một lỳc khụng phải là khú.
Lược đồ cơ bản là tạo ra một ServerSocket đơn trong server và gọi Accept() để chờ cỏc kết nối mới. Khi Accept() trả về, bạn cú được Socket và dựng nú để tạo ra
cỏc tiến trỡnh mới làm việc với server giống những client riờng rẽ. Sau đú lai gọi Accept() để chờ đợi những kết nối mới.
using System; using System.Net;
using System.Net.Sockets; using System.IO;
using System.Threading;
public class MultiJabberServer {
// Choose a port outside of the range 1-1024: public static readonly int PORT = 1711;
public static void Main(){ new MultiJabberServer(); }
public MultiJabberServer(){
TcpListener server = new TcpListener(PORT); try {
server.Start();
Console.WriteLine("Started: " + server); while (true) {
// Blocks until a connection occurs:
TcpClient cnxn = server.AcceptTcpClient(); Console.WriteLine(
"Connection accepted: "+ cnxn); new ServeOneJabber(cnxn);
}
} catch (Exception ex) { Console.WriteLine(ex); } finally { server.Stop(); } } } class ServeOneJabber { TcpClient cnxn; internal ServeOneJabber(TcpClient cnxn){ this.cnxn = cnxn; ThreadStart oneServer = new ThreadStart(Run);
Thread svrThread = new Thread(oneServer); svrThread.Start();
}
public void Run(){ try {
StreamReader reader =
StreamWriter writer =
new StreamWriter(cnxn.GetStream()); writer.AutoFlush = true;
Console.WriteLine("Beginning receive loop"); while (true) { String str = reader.ReadLine(); if (str == "END") break; Console.WriteLine("Echoing: " + str); writer.WriteLine(str); } } finally { cnxn.Close(); } } }///:~
MultiJabberServer() khởi tạo bắt đầu TcpListener và chờ đợi cho cỏc kết nối được tạo ra. Khi kết nối được tạo ra, nú sẽ khởi tạo một đối tượng ServerOneJabber, qua đú TcpClient là đại diện cho kết nối mới. ServerOneJabber() khởi tạo chứa TcpClient cnxn là biến instance cựng tờn. Tạo ra một ThreadStart đại diện và bắt đầu tiến trỡnh mới Thread. Sự khởi tạo này thành cụng một cỏch nhanh chúng và cho phộp MultiJabberServer tiếp tục lắng nghe chờ cỏc yờu cầu kết nối khỏc. Phương thức ServerOneJabber.Run() là phương thức tạo một tiến trỡnh đại diện và nú chứa đựng cỏc nhận dạng đối với cỏc JabberServer chỉ in ra màn hỡnh console những gỡ gửi đến nú. Trỏch nhiệm đúng TcpClient khụng thuộc về MultiJabberServer mà chỉ khởi tạo nú. Đỳng hơn là phương thức ServerOneJabber.Run() cú sự phản hồi khi gọi TcpClient.Close() bờn trong khối mệnh đề finally. Nờn chỳ ý đến tớnh đơn giản của MultiJabberServer. Ngay trước khi một TcpListener được khởi tạo và AcceptTcpClient được gọi cho phộp tạo ra một kết nối mới. Nhưng lỳc nàygiỏ trị trả về (của TcpClient) được tạo ra từ sự khởi tạo của ServerOneJabber, cỏi mà tạo ra tiến trỡnh mới và bắt tay kết nối. Khi kết nối kết thỳc thỡ tiến trỡnh này cũng bị hủy.