Giáo trình Lập trình mạng (Phần 1)
Tóm tắt Giáo trình Lập trình mạng (Phần 1): ... = Encoding.ASCII.GetString(data, 0, rec); Console.WriteLine(s); } client.Close(); } } Chương trình Server sử dụng NetworkStream: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; class Prog...tSend.Clear(); if (txtSend.Text.ToUpper().Equals("QUIT")) this.Dispose(); } private void btConnect_Click(object sender, EventArgs e) { Thread tuyen = new Thread(new ThreadStart(NhanDl)); tuyen.Start(); } private void NhanDl() { UdpClient receiver = new UdpClient(int.Parse(txt...eceive(data); if (recv == 0) break; Console.WriteLine( Encoding.ASCII.GetString(data, 0, recv)); client.Send(data, recv, 0); } } Console.WriteLine("Disconnected from {0}", newclient.Address); client.Close(); newsock.Close(); } } Sau đây chúng ta sẽ viết một c...
ngData); } sock.Close(); } } 2.5. Sử dụng Thread trong các ứng dụng mạng 40 Một số khái niệm - ða nhiệm (Multitasking): Là khả năng hệ điêu hành làm nhiều cơng việc tại một thời điểm - Tiến trình (Process): Khi chạy một ứng dụng, hệ điều hành sẽ cấp phát riêng cho ứng dụng đĩ bộ nhớ và các tài nguyên khác. Bộ nhớ và tài nguyên vật lý riêng biệt này được gọi là một tiến trình. Các tài nguyên và bộ nhớ của một tiến trình thì chỉ tiến trình đĩ được phép truy cập. - Tuyến (Thread): Trong hệ thống, một tiến trình cĩ thể cĩ một hoặc nhiều chuỗi thực hiện tách biệt nhau và cĩ thể chạy đồng thời. Mỗi chuỗi thực hiện này được gọi là một tuyến (Thread). Trong một ứng dụng, Thread khởi tạo đầu tiên gọi là Thread sơ cấp hay Thread chính. 2.5.1. Sử dụng Thread trong chương trình .Net ðể sử dụng Thread trong .Net ta sử dụng NameSpace System.Threading - Một số phương thức thường dùng Public Method Name Mơ tả Abort() Kết thúc Thread Join() Buộc chương trình phải chờ cho thread kết thúc (Block) thì mới thực hiện tiếp (các câu lệnh đứng sau Join). Resume() Tiếp tục chạy thread đã bị tạm ngưng - suspended. Sleep() Static method : Tạm dừng thread trong một khoảng thời gian. Start() Bắt đầu chạy (khởi động) một thread. Sau khi gọi phương thức này, trạng thái của thread chuyển từ trạng thái hiện hành sang Running. Suspend() Tạm ngưng (nghỉ) thread. (Phương thức này đã bị loại khỏi phiên bản VS.NET 2005) - Một số thuộc tính thường dùng: Public Property Name Mơ tả CurrentThread This static property: Trả về thread hiện hành đang chạy. IsAlive Trả về giá trị cho biết trạng thái thực thi của thread hiện hành. IsBackground Sets or gets giá trị cho biết là thread là background hay foreground thread. IsThreadPoolThread Gets a value indicating whether a thread is part of a thread pool. Priority Sets or gets giá trị để chỉ định độ ưu tiên (dành nhiều hay ít CPU cho thread). Cao nhất là 4, thấp nhất là 0. 41 Public Property Name Mơ tả ThreadState Lấy về trạng thái của thread (đang dừng, hay đang chạy) - Tạo một tuyến trong C# Thread newThread=newThread(new ThreadStart(newMethod)); . } void newMethod() { . . . } 2.5.2. Sử dụng Thread trong các chương trình Server - ða tuyên hay được ứng dụng trong các chương trình Server, các chương trình địi hỏi tại một thời điểm chấp nhận nhiều kết nối đến từ các Client. - ðể các chương trình Server cĩ thể xử lý nhiều Client tại một thời điểm ta cĩ mơ hình ứng dụng đa tuyến như sau: Sau đây chúng ta viết lại chương trình DateTimeServer cĩ sử dụng Thread như sau: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.Threading; using System.IO; class Program { static void Main(string[] args) { IPEndPoint iep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2009); TcpListener server = new TcpListener(iep); server.Start(); while (true) { 42 //chap nhan ket noi TcpClient client= server.AcceptTcpClient(); //Tao ra tuyen moi de xu ly moi Client new ClientThread(client); } server.Stop(); } } class ClientThread { private Thread tuyen; private TcpClient client; public ClientThread(TcpClient client) { this.client = client; tuyen = new Thread(new ThreadStart(GuiNhanDL)); tuyen.Start(); } private void GuiNhanDL() { StreamReader sr = new StreamReader(client.GetStream()); StreamWriter sw= new StreamWriter(client.GetStream()); string kq=""; while(true) { string s=sr.ReadLine(); s=s.ToUpper(); if(s.Equals("QUIT")) break; if(s.Equals("GETDATE")) kq=DateTime.Now.ToString("dd/MM/yyyy"); else if(s.Equals("GETTIME")) kq=DateTime.Now.ToString("hh:mm:ss"); else kq="Khong hieu lenh"; sw.WriteLine(kq); sw.Flush(); } client.Close(); } } 2.5.3. Sử dụng Thread để gửi/nhận dữ liệu Ứng dụng đa tuyến trong việc gửi nhận dữ liệu chúng ta viết chương trình Chat theo giao thức TCP như sau: 43 Ứng dụng mơ hình xử lý sự kiện của Windows và đa tuyến và Socket khơng đồng bộ ta chỉ cần viết một chương trình sau đĩ dịch ra, ta chạy ứng dụng nhấn Listen nĩ sẽ lắng nghe trong vai trị Server cịn khi ta chạy và nhấn Connect nĩ sẽ đĩng vai trị Client và kết nối tới Server. Văn bản chương trình như sau: using System; using System.Drawing; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; 44 using System.Windows.Forms; class TcpChat:Form { private static TextBox newText; private static ListBox results; private static Socket client; private static byte[] data = new byte[1024]; public TcpChat() { Text = "TCP Chat Program"; Size = new Size(400, 380); Label label1 = new Label(); label1.Parent = this; label1.Text = "Enter text string:"; label1.AutoSize = true; label1.Location = new Point(10, 30); newText = new TextBox(); newText.Parent = this; newText.Size = new Size(200, 2 * Font.Height); newText.Location = new Point(10, 55); results = new ListBox(); results.Parent = this; results.Location = new Point(10, 85); results.Size = new Size(360, 18 * Font.Height); Button sendit = new Button(); sendit.Parent = this; sendit.Text = "Send"; sendit.Location = new Point(220,52); sendit.Size = new Size(5 * Font.Height, 2 * Font.Height); sendit.Click += new EventHandler(ButtonSendOnClick); Button connect = new Button(); connect.Parent = this; connect.Text = "Connect"; connect.Location = new Point(295, 20); connect.Size = new Size(6 * Font.Height, 2 * Font.Height); connect.Click += new EventHandler(ButtonConnectOnClick); Button listen = new Button(); listen.Parent = this; listen.Text = "Listen"; listen.Location = new Point(295,52); listen.Size = new Size(6 * Font.Height, 2 * Font.Height); listen.Click += new EventHandler(ButtonListenOnClick); } void ButtonListenOnClick(object obj, EventArgs ea) { results.Items.Add("Listening for a client..."); Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 45 IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050); newsock.Bind(iep); newsock.Listen(5); newsock.BeginAccept(new AsyncCallback(AcceptConn), newsock); } void ButtonConnectOnClick(object obj, EventArgs ea) { results.Items.Add("Connecting..."); client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint iep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050); client.BeginConnect(iep, new AsyncCallback(Connected), client); } void ButtonSendOnClick(object obj, EventArgs ea) { byte[] message = Encoding.ASCII.GetBytes(newText.Text); newText.Clear(); client.BeginSend(message, 0, message.Length, 0, new AsyncCallback(SendData), client); } void AcceptConn(IAsyncResult iar) { Socket oldserver = (Socket)iar.AsyncState; client = oldserver.EndAccept(iar); results.Items.Add("Connection from: " + client.RemoteEndPoint.ToString()); Thread receiver = new Thread(new ThreadStart(ReceiveData)); receiver.Start(); } void Connected(IAsyncResult iar) { try { client.EndConnect(iar); results.Items.Add("Connected to: " + client.RemoteEndPoint.ToString()); Thread receiver = new Thread(new ThreadStart(ReceiveData)); receiver.Start(); } catch (SocketException) { results.Items.Add("Error connecting"); } } void SendData(IAsyncResult iar) { Socket remote = (Socket)iar.AsyncState; int sent = remote.EndSend(iar); } void ReceiveData() { int recv; 46 string stringData; while (true) { recv = client.Receive(data); stringData = Encoding.ASCII.GetString(data, 0, recv); if (stringData == "bye") break; results.Items.Add(stringData); } stringData = "bye"; byte[] message = Encoding.ASCII.GetBytes(stringData); client.Send(message); client.Close(); results.Items.Add("Connection stopped"); return; } public static void Main() { Application.Run(new TcpChat()); } } 2.5.4. Sử dụng ThreadPool trong các chương trình .Net Method Description BindHandle() Binds an operating system handle to the thread pool GetAvailableThreads() Gets the number of worker threads available for use in the thread pool GetMaxThreads() Gets the maximum number of worker threads available in the thread pool QueueUserWorkItem() Queues a user delegate to the thread pool RegisterWaitForSingleObject() Registers a delegate waiting for a WaitHandle object UnsafeQueueUserWorkItem() Queues an unsafe user delegate to the thread pool but does not propagate the calling stack onto the worker thread UnsafeRegisterWaitForSingleObject() Registers an unsafe delegate waiting for a WaitHandle object using System; using System.Threading; class ThreadPoolSample { 47 public static void Main() { ThreadPoolSample tps = new ThreadPoolSample(); } public ThreadPoolSample() { int i; ThreadPool.QueueUserWorkItem(new WaitCallback(Counter)); ThreadPool.QueueUserWorkItem(new WaitCallback(Counter2)); for(i = 0; i < 10; i++) { Console.WriteLine("main: {0}", i); Thread.Sleep(1000); } } void Counter(object state) { int i; for (i = 0; i < 10; i++) { Console.WriteLine(" thread: {0}", i); Thread.Sleep(2000); } } void Counter2(object state) { int i; for (i = 0; i < 10; i++) { Console.WriteLine(" thread2: {0}", i); Thread.Sleep(3000); } } } 2.5.5. Sử dụng ThreadPool trong các chương trình Server using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; class ThreadPoolTcpSrvr { private TcpListener client; public ThreadPoolTcpSrvr() { client = new TcpListener(9050); client.Start(); Console.WriteLine("Waiting for clients..."); while(true) { while (!client.Pending()) { Thread.Sleep(1000); } ConnectionThread newconnection = new ConnectionThread(); newconnection.threadListener = this.client; ThreadPool.QueueUserWorkItem(new WaitCallback(newconnection.HandleConnection)); } } public static void Main() { ThreadPoolTcpSrvr tpts = new ThreadPoolTcpSrvr(); 48 } } class ConnectionThread { public TcpListener threadListener; private static int connections = 0; public void HandleConnection(object state) { int recv; byte[] data = new byte[1024]; TcpClient client = threadListener.AcceptTcpClient(); NetworkStream ns = client.GetStream(); connections++; Console.WriteLine("New client accepted: {0} active connections", connections); string welcome = "Welcome to my test server"; data = Encoding.ASCII.GetBytes(welcome); ns.Write(data, 0, data.Length); while(true) { data = new byte[1024]; recv = ns.Read(data, 0, data.Length); if (recv == 0) break; ns.Write(data, 0, recv); } ns.Close(); client.Close(); connections—; Console.WriteLine("Client disconnected: {0} active connections", connections); } } 2.6. Kỹ thuật IP Multicasting 2.6.1. Broadcasting là gì? Broadcast, tiếng Việt gọi là quảng bá. Trong hệ thống mạng hữu tuyến, quảng bá là thuật ngữ dùng để chỉ việc gửi một gĩi thơng tin đến tất các nút mạng trong mạng. ðể thực hiện hình thức quảng bá, địa chỉ đến của gĩi tin sẽ là địa chỉ quảng bá. Cĩ hai loại là: Local Broadcast và Global Broadcast 2.6.2. Sử dụng Broadcasting để gửi dữ liệu đến nhiều máy trong mạng cục bộ Gửi gĩi dữ liệu Broadcast using System; using System.Net; using System.Net.Sockets; using System.Text; class BadBroadcast { public static void Main() { Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint iep = new IPEndPoint(IPAddress.Broadcast, 9050); byte[] data = Encoding.ASCII.GetBytes("This is a test message"); sock.SendTo(data, iep); sock.Close(); } 49 } Chúng ta phải thiết lập như sau: class Broadcst { public static void Main() { Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint iep1 = new IPEndPoint(IPAddress.Broadcast, 9050); IPEndPoint iep2 = new IPEndPoint(IPAddress.Parse("192.168.1.255"), 9050); string hostname = Dns.GetHostName(); byte[] data = Encoding.ASCII.GetBytes(hostname); sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); sock.SendTo(data, iep1); sock.SendTo(data, iep2); sock.Close(); } } Nhận gĩi dữ liệu Broadcast class RecvBroadcst { public static void Main() { Socket sock = new Socket(AddressFamily.InterNetwork,SocketType.Dgram, ProtocolType.Udp); IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050); sock.Bind(iep); EndPoint ep = (EndPoint)iep; Console.WriteLine("Ready to receive"); byte[] data = new byte[1024]; int recv = sock.ReceiveFrom(data, ref ep); string stringData = Encoding.ASCII.GetString(data, 0, recv); Console.WriteLine("received: {0} from: {1}", stringData, ep.ToString()); data = new byte[1024]; recv = sock.ReceiveFrom(data, ref ep); stringData = Encoding.ASCII.GetString(data, 0, recv); Console.WriteLine("received: {0} from: {1}",stringData, ep.ToString()); sock.Close(); } } 2.6.3. Multicasting là gì? Một địa chỉ multicast cho phép thiết bị gửi dữ liệu tới một tập xác định trước các host, được biết đến như các nhĩm multicast, trong các mạng con khác nhau. Một số địa chỉ Multicast ðịa chỉ multicast Chức năng 224.0.0.0 ðịa chỉ cơ sở 224.0.0.1 Tất cả các hệ thống trên mạng con này 224.0.0.2 Tất cả các Router trên mạng con này 50 224.0.0.5 Các DR trong OSPF 224.0.1.9 Nhĩm địa chỉ RIPv2 224.0.1.24 Nhĩm địa chỉ WINS server Cĩ 2 kỹ thuật Multicast được sử dụng + Peer to Peer + Central Server 2.6.4. Socket Multicasting trong .Net Sử dụng phương thức SetSocketOption() 51 Socket option cĩ thể được sử dụng để Thêm một Socket vào nhĩm Multicast Loại một Socket khỏi nhĩm Multicast SetSocketOption(SocketOptionLevel,SocketOptionName, optionValue) SocketOptionName AddMembership DropMembership Sử dụng phương thức SetSocketOption() Socket option cĩ thể được sử dụng để optionValue là một đối tượng của lớp MulticastOption MulticastOption(IPAddress) MulticastOption(IPAddress,IPAddress) Ví dụ thêm một Socket vào nhĩm Multicast 224.100.0.1 sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("224.100.0.1")); Gửi dữ liệu Multicast class MultiSend{ public static void Main() { Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint iep = new IPEndPoint(IPAddress.Parse("224.100.0.1"), 9050); byte[] data = Encoding.ASCII.GetBytes("This is a test message"); server.SendTo(data, iep); server.Close(); } } Nhận dữ liệu Multicast class MultiRecv{ public static void Main() { Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); Console.WriteLine("Ready to receive"); IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050); EndPoint ep = (EndPoint)iep; sock.Bind(iep); sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("224.100.0.1"))); byte[] data = new byte[1024]; int recv = sock.ReceiveFrom(data, ref ep); string stringData = Encoding.ASCII.GetString(data, 0, recv); Console.WriteLine("received: {0} from: {1}", stringData, ep.ToString()); sock.Close(); } } 52 Gửi dữ liệu Multicast với TTL class NewMultiSend{ public static void Main() { Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9051); IPEndPoint iep2 = new IPEndPoint(IPAddress.Parse("224.100.0.1"), 9050); server.Bind(iep); byte[] data = Encoding.ASCII.GetBytes("This is a test message"); server.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("224.100.0.1"))); server.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 50); server.SendTo(data, iep2); server.Close(); } } Multicast với lớp UdpClient JoinMulticastGroup() DropMulticastGroup() JoinMulticastGroup() là phương thức overload JoinMulticastGroup(IPAddress) JoinMulticastGroup(IPAddress, int) class UdpClientMultiSend{ public static void Main() { UdpClient sock = new UdpClient(); IPEndPoint iep = new IPEndPoint(IPAddress.Parse("224.100.0.1"), 9050); byte[] data = Encoding.ASCII.GetBytes("This is a test message"); sock.Send(data, data.Length, iep); sock.Close(); } } class UdpClientMultiRecv { public static void Main() { UdpClient sock = new UdpClient(9050); Console.WriteLine("Ready to receive"); sock.JoinMulticastGroup(IPAddress.Parse("224.100.0.1"), 50); IPEndPoint iep = new IPEndPoint(IPAddress.Any, 0); byte[] data = sock.Receive(ref iep); string stringData = Encoding.ASCII.GetString(data, 0, data.Length); Console.WriteLine("received: {0} from: {1}", stringData, iep.ToString()); sock.Close(); } } 53 2.7 Bài tập áp dụng class MulticastChat : Form{ TextBox newText; ListBox results; Socket sock; Thread receiver; IPEndPoint multiep = new IPEndPoint(IPAddress.Parse("224.100.0.1"), 9050); public MulticastChat() { Text = "Multicast Chat Program"; Size = new Size(400, 380); Label label1 = new Label(); label1.Parent = this; label1.Text = "Enter text string:"; label1.AutoSize = true; label1.Location = new Point(10, 30); newText = new TextBox(); newText.Parent = this; newText.Size = new Size(200, 2 * Font.Height); newText.Location = new Point(10, 55); results = new ListBox(); results.Parent = this; results.Location = new Point(10, 85); results.Size = new Size(360, 18 * Font.Height); Button sendit = new Button(); sendit.Parent = this; sendit.Text = "Send"; sendit.Location = new Point(220, 52); sendit.Size = new Size(5 * Font.Height, 2 * Font.Height); sendit.Click += new EventHandler(ButtonSendOnClick); Button closeit = new Button(); closeit.Parent = this; closeit.Text = "Close"; closeit.Location = new Point(290, 52); closeit.Size = new Size(5 * Font.Height, 2 * Font.Height); closeit.Click += new EventHandler(ButtonCloseOnClick); sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050); sock.Bind(iep); sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, 54 new MulticastOption(IPAddress.Parse("224.100.0.1"))); receiver = new Thread(new ThreadStart(packetReceive)); receiver.IsBackground = true; receiver.Start(); } void ButtonSendOnClick(object obj, EventArgs ea) { byte[] message = Encoding.ASCII.GetBytes(newText.Text); newText.Clear(); sock.SendTo(message, SocketFlags.None, multiep); } void ButtonCloseOnClick(object obj, EventArgs ea) { receiver.Abort(); sock.Close(); Close(); } void packetReceive() { EndPoint ep = (EndPoint)multiep; byte[] data = new byte[1024]; string stringData; int recv; while (true) { recv = sock.ReceiveFrom(data, ref ep); stringData = Encoding.ASCII.GetString(data, 0, recv); results.Items.Add("from " + ep.ToString() + ": " + stringData); } } public static void Main() { Application.Run(new MulticastChat()); } }
File đính kèm:
- giao_trinh_lap_trinh_mang_phan_1.pdf