Giáo trình Lập trình mạng (Phần 1)

CHƯƠNG 1: CÁC KIẾN THỨC CƠ BẢN VỀ MẠNG MÁY TÍNH

1.1. Mô hình tham khảo 7 tầng OSI

Mô hình kết nối hệ thống mở ñược Tổ chức quốc tế về tiêu chuẩn hoá ISO

(International Organizaiton for Standardization) ñưa ra nhằm cung cấp một mô hình

chuẩn cho các nhà sản xuất và cung cấp sản phẩm viễn thông áp dụng theo ñể phát

triển các sản phẩm viễn thông. Ý tưởng mô hình hoá ñược tạo ra còn nhằm hỗ trợ cho

việc kết nối giữa các hệ thống và modun hoá các thành phần phục vụ mạng viến thông.

a. Chức năng của mô hình OSI:

- Cung cấp kiến thức về hoạt ñộng của kết nối liên mạng

- ðưa ra trình tự công việc ñể thiết lập và thực hiện một giao thức cho kết nối các thiết

bị trên mạng.

pdf54 trang | Chia sẻ: phuongt97 | Lượt xem: 336 | Lượt tải: 0download
Bạn đang xem trước 20 trang nội dung tài liệu Giáo trình Lập trình mạng (Phần 1), để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
ngphươngthcSelect() ñchpnhn2ktniñntclientvàxlýtngktni. ChươngtrìnhSelectServer: usingSystem; usingSystem.Collections; usingSystem.Net; usingSystem.Net.Sockets; usingSystem.Text; classSelectTcpSrvr { publicstaticvoidMain() { ArrayListsockList=newArrayList(2); ArrayListcopyList=newArrayList(2); Socketmain=newSocket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp); IPEndPointiep=newIPEndPoint(IPAddress.Any,9050); byte[]data=newbyte[1024]; stringstringData; 37 intrecv; main.Bind(iep); main.Listen(2); Console.WriteLine("Waitingfor2clients..."); Socketclient1=main.Accept(); IPEndPointiep1=(IPEndPoint)client1.RemoteEndPoint; client1.Send(Encoding.ASCII.GetBytes("Welcometomyserver")); Console.WriteLine("Connectedto{0}",iep1.ToString()); sockList.Add(client1); Console.WriteLine("Waitingfor1moreclient..."); Socketclient2=main.Accept(); IPEndPointiep2=(IPEndPoint)client2.RemoteEndPoint; client2.Send(Encoding.ASCII.GetBytes("Welcometomyserver")); Console.WriteLine("Connectedto{0}",iep2.ToString()); sockList.Add(client2); main.Close(); while(true) { copyList=newArrayList(sockList); Console.WriteLine("Monitoring{0}sockets...",copyList.Count); Socket.Select(copyList,null,null,10000000); foreach(SocketclientincopyList) { data=newbyte[1024]; recv=client.Receive(data); stringData=Encoding.ASCII.GetString(data,0,recv); Console.WriteLine("Received:{0}",stringData); if(recv==0) { iep=(IPEndPoint)client.RemoteEndPoint; Console.WriteLine("Client{0}disconnected.",iep.ToString()); client.Close(); sockList.Remove(client); if(sockList.Count==0) { Console.WriteLine("Lastclientdisconnected,bye"); return; } } else client.Send(data,recv,SocketFlags.None); 38 } } } } ChươngtrìnhClient: usingSystem; usingSystem.Collections; usingSystem.Net; usingSystem.Net.Sockets; usingSystem.Text; classSelectTcpClient { publicstaticvoidMain() { Socketsock=newSocket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp); IPEndPointiep=newIPEndPoint(IPAddress.Parse("127.0.0.1"),9050); byte[]data=newbyte[1024]; stringstringData; intrecv; sock.Connect(iep); Console.WriteLine("Connectedtoserver"); recv=sock.Receive(data); stringData=Encoding.ASCII.GetString(data,0,recv); Console.WriteLine("Received:{0}",stringData); while(true) { stringData=Console.ReadLine(); if(stringData=="exit") break; data=Encoding.ASCII.GetBytes(stringData); sock.Send(data,data.Length,SocketFlags.None); data=newbyte[1024]; recv=sock.Receive(data); stringData=Encoding.ASCII.GetString(data,0,recv); Console.WriteLine("Received:{0}",stringData); } sock.Close(); } } 2.5.SdngThreadtrongcácngdngmng 39 Mtskháinim ðanhim(Multitasking):Làkhnănghñiêuhànhlàmnhiucôngvictimtthi ñim Tintrình(Process):Khichymtngdng,hñiuhànhscpphátriêngchong dngñóbnhvàcáctàinguyênkhác.Bnhvàtàinguyênvtlýriêngbitnày ñưcgilàmttintrình.Cáctàinguyênvàbnhcamttintrìnhthìchtin trìnhñóñưcphéptruycp. Tuyn(Thread):Tronghthng,mttintrìnhcóthcómthocnhiuchuithc hintáchbitnhauvàcóthchyñngthi.Michuithchinnàyñưcgilàmt tuyn(Thread).Trongmtngdng,ThreadkhitoñutiêngilàThreadsơcp hayThreadchính. 2.5.1.SdngThreadtrongchươngtrình.Net ðsdngThreadtrong.NettasdngNameSpaceSystem.Threading Mtsphươngthcthưngdùng PublicMethod Môt Name Abort() KtthúcThread Join() Bucchươngtrìnhphichchothreadktthúc(Block)thìmithchin tip(cáccâulnhñngsauJoin). Resume() Tiptcchythreadñãbtmngưngsuspended. Sleep() Staticmethod:Tmdngthreadtrongmtkhongthigian. Start() Btñuchy(khiñng)mtthread.Saukhigiphươngthcnày,trng tháicathreadchuynttrngtháihinhànhsangRunning. Suspend() Tmngưng(ngh)thread.(Phươngthcnàyñãbloikhiphiênbn VS.NET2005) Mtsthuctínhthưngdùng: PublicProperty Môt Name CurrentThread Thisstaticproperty:Trvthreadhinhànhñangchy. IsAlive Trvgiátrchobittrngtháithcthicathreadhinhành. IsBackground Setsorgetsgiátrchobitlàthreadlàbackgroundhayforeground thread. IsThreadPoolThread Getsavalueindicatingwhetherathreadispartofathreadpool. Priority Setsorgetsgiátrñchñnhñưutiên(dànhnhiuhayítCPUcho thread).Caonhtlà4,thpnhtlà0. 40 PublicProperty Môt Name ThreadState Lyvtrngtháicathread(ñangdng,hayñangchy) TomttuyntrongC# ThreadnewThread=newThread(newThreadStart(newMethod)); . } voidnewMethod(){ ... } 2.5.2. SdngThreadtrongcácchươngtrìnhServer ðatuyênhayñưcngdngtrongcácchươngtrìnhServer,cácchươngtrình ñòihitimtthiñimchpnhnnhiuktniñntcácClient. ðcácchươngtrìnhServercóthxlýnhiuClienttimtthiñimtacó môhìnhngdngñatuynnhưsau: SauñâychúngtavitlichươngtrìnhDateTimeServercósdngThreadnhưsau: usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; usingSystem.Net; usingSystem.Net.Sockets; usingSystem.Threading; usingSystem.IO; classProgram{ staticvoidMain(string[]args){ IPEndPointiep=newIPEndPoint(IPAddress.Parse("127.0.0.1"),2009); TcpListenerserver=newTcpListener(iep); server.Start(); while(true){ 41 //chapnhanketnoi TcpClientclient=server.AcceptTcpClient(); //TaoratuyenmoidexulymoiClient newClientThread(client); } server.Stop(); } } classClientThread{ privateThreadtuyen; privateTcpClientclient; publicClientThread(TcpClientclient){ this.client=client; tuyen=newThread(newThreadStart(GuiNhanDL)); tuyen.Start(); } privatevoidGuiNhanDL(){ StreamReadersr=newStreamReader(client.GetStream()); StreamWritersw=newStreamWriter(client.GetStream()); stringkq=""; while(true) { strings=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="Khonghieulenh"; sw.WriteLine(kq); sw.Flush(); } client.Close(); } } 2.5.3.SdngThreadñgi/nhndliu ngdngñatuyntrongvicginhndliuchúngtavitchươngtrìnhChat theogiaothcTCPnhưsau: 42 ngdngmôhìnhxlýskincaWindowsvàñatuynvàSocketkhông ñngbtachcnvitmtchươngtrìnhsauñódchra,tachyngdngnhnListen nóslngnghetrongvaitròServercònkhitachyvànhnConnectnósñóngvai tròClientvàktnitiServer. Vănbnchươngtrìnhnhưsau: usingSystem; usingSystem.Drawing; usingSystem.Net; usingSystem.Net.Sockets; usingSystem.Text; usingSystem.Threading; 43 usingSystem.Windows.Forms; classTcpChat:Form { privatestaticTextBoxnewText; privatestaticListBoxresults; privatestaticSocketclient; privatestaticbyte[]data=newbyte[1024]; publicTcpChat() { Text="TCPChatProgram"; Size=newSize(400,380); Labellabel1=newLabel(); label1.Parent=this; label1.Text="Entertextstring:"; label1.AutoSize=true; label1.Location=newPoint(10,30); newText=newTextBox(); newText.Parent=this; newText.Size=newSize(200,2*Font.Height); newText.Location=newPoint(10,55); results=newListBox(); results.Parent=this; results.Location=newPoint(10,85); results.Size=newSize(360,18*Font.Height); Buttonsendit=newButton(); sendit.Parent=this; sendit.Text="Send"; sendit.Location=newPoint(220,52); sendit.Size=newSize(5*Font.Height,2*Font.Height); sendit.Click+=newEventHandler(ButtonSendOnClick); Buttonconnect=newButton(); connect.Parent=this; connect.Text="Connect"; connect.Location=newPoint(295,20); connect.Size=newSize(6*Font.Height,2*Font.Height); connect.Click+=newEventHandler(ButtonConnectOnClick); Buttonlisten=newButton(); listen.Parent=this; listen.Text="Listen"; listen.Location=newPoint(295,52); listen.Size=newSize(6*Font.Height,2*Font.Height); listen.Click+=newEventHandler(ButtonListenOnClick); } voidButtonListenOnClick(objectobj,EventArgsea) { results.Items.Add("Listeningforaclient..."); Socketnewsock=newSocket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp); 44 IPEndPointiep=newIPEndPoint(IPAddress.Any,9050); newsock.Bind(iep); newsock.Listen(5); newsock.BeginAccept(newAsyncCallback(AcceptConn),newsock); } voidButtonConnectOnClick(objectobj,EventArgsea) { results.Items.Add("Connecting..."); client=newSocket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp); IPEndPointiep=newIPEndPoint(IPAddress.Parse("127.0.0.1"),9050); client.BeginConnect(iep,newAsyncCallback(Connected),client); } voidButtonSendOnClick(objectobj,EventArgsea) { byte[]message=Encoding.ASCII.GetBytes(newText.Text); newText.Clear(); client.BeginSend(message,0,message.Length,0, newAsyncCallback(SendData),client); } voidAcceptConn(IAsyncResultiar) { Socketoldserver=(Socket)iar.AsyncState; client=oldserver.EndAccept(iar); results.Items.Add("Connectionfrom:"+client.RemoteEndPoint.ToString()); Threadreceiver=newThread(newThreadStart(ReceiveData)); receiver.Start(); } voidConnected(IAsyncResultiar) { try { client.EndConnect(iar); results.Items.Add("Connectedto:"+client.RemoteEndPoint.ToString()); Threadreceiver=newThread(newThreadStart(ReceiveData)); receiver.Start(); }catch(SocketException) { results.Items.Add("Errorconnecting"); } } voidSendData(IAsyncResultiar) { Socketremote=(Socket)iar.AsyncState; intsent=remote.EndSend(iar); } voidReceiveData() { intrecv; 45 stringstringData; 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("Connectionstopped"); return; } publicstaticvoidMain() { Application.Run(newTcpChat()); } } 2.5.4.SdngThreadPooltrongcácchươngtrình.Net Method Description BindHandle() Bindsanoperatingsystemhandletothe threadpool GetAvailableThreads() Getsthenumberofworkerthreads availableforuseinthethreadpool GetMaxThreads() Getsthemaximumnumberofworker threadsavailableinthethreadpool QueueUserWorkItem() Queuesauserdelegatetothethread pool RegisterWaitForSingleObject() Registersadelegatewaitingfora WaitHandleobject UnsafeQueueUserWorkItem() Queuesanunsafeuserdelegatetothe threadpoolbutdoesnotpropagatethe callingstackontotheworkerthread UnsafeRegisterWaitForSingleObject() Registersanunsafedelegatewaitingfor aWaitHandleobject using System; using System.Threading; class ThreadPoolSample { 46 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.SdngThreadPooltrongcácchươngtrìnhServer 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(); 47 } } 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.KthutIPMulticasting 2.6.1.Broadcastinglàgì? Broadcast,tingVitgilàqungbá.Tronghthngmnghutuyn,qungbálà thutngdùngñchvicgimtgóithôngtinñnttcácnútmngtrongmng.ð thchinhìnhthcqungbá,ñachñncagóitinslàñachqungbá. Cóhailoilà:LocalBroadcastvàGlobalBroadcast 2.6.2.SdngBroadcastingñgidliuñnnhiumáytrongmngccb GigóidliuBroadcast usingSystem; usingSystem.Net; usingSystem.Net.Sockets; usingSystem.Text; classBadBroadcast{ publicstaticvoidMain(){ Socketsock=newSocket(AddressFamily.InterNetwork, SocketType.Dgram,ProtocolType.Udp); IPEndPointiep=newIPEndPoint(IPAddress.Broadcast,9050); byte[]data=Encoding.ASCII.GetBytes("Thisisatestmessage"); sock.SendTo(data,iep); sock.Close(); } 48 } Chúngtaphithitlpnhưsau: classBroadcst{ publicstaticvoidMain(){ Socketsock=newSocket(AddressFamily.InterNetwork,SocketType.Dgram, ProtocolType.Udp); IPEndPointiep1=newIPEndPoint(IPAddress.Broadcast,9050); IPEndPointiep2=newIPEndPoint(IPAddress.Parse("192.168.1.255"),9050); stringhostname=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(); } } NhngóidliuBroadcast classRecvBroadcst{ publicstaticvoidMain(){ Socketsock=newSocket(AddressFamily.InterNetwork,SocketType.Dgram, ProtocolType.Udp); IPEndPointiep=newIPEndPoint(IPAddress.Any,9050); sock.Bind(iep);EndPointep=(EndPoint)iep; Console.WriteLine("Readytoreceive");byte[]data=newbyte[1024]; intrecv=sock.ReceiveFrom(data,refep); stringstringData=Encoding.ASCII.GetString(data,0,recv); Console.WriteLine("received:{0}from:{1}",stringData,ep.ToString()); data=newbyte[1024];recv=sock.ReceiveFrom(data,refep); stringData=Encoding.ASCII.GetString(data,0,recv); Console.WriteLine("received:{0}from:{1}",stringData,ep.ToString()); sock.Close(); } } 2.6.3.Multicastinglàgì? Mtñachmulticastchophépthitbgidliutimttpxácñnhtrưccáchost, ñưcbitñnnhưcácnhómmulticast,trongcácmngconkhácnhau. MtsñachMulticast ðachmulticast Chcnăng 224.0.0.0 ðachcơs 224.0.0.1 Ttccáchthngtrênmngconnày 224.0.0.2 TtccácRoutertrênmngconnày 49 224.0.0.5 CácDRtrongOSPF 224.0.1.9 NhómñachRIPv2 224.0.1.24 NhómñachWINSserver Có2kthutMulticastñưcsdng +PeertoPeer +CentralServer 2.6.4.SocketMulticastingtrong.Net  SdngphươngthcSetSocketOption() 50  Socketoptioncóthñưcsdngñ  ThêmmtSocketvàonhómMulticast  LoimtSocketkhinhómMulticast  SetSocketOption(SocketOptionLevel,SocketOptionName,optionValue)  SocketOptionName  AddMembership  DropMembership  SdngphươngthcSetSocketOption()  Socketoptioncóthñưcsdngñ  optionValuelàmtñitưngcalpMulticastOption MulticastOption(IPAddress)MulticastOption(IPAddress,IPAddress)  VídthêmmtSocketvàonhómMulticast224.100.0.1 sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,new MulticastOption(IPAddress.Parse("224.100.0.1")); GidliuMulticast classMultiSend{ publicstaticvoidMain(){ Socketserver=newSocket(AddressFamily.InterNetwork, SocketType.Dgram,ProtocolType.Udp); IPEndPointiep=new IPEndPoint(IPAddress.Parse("224.100.0.1"),9050); byte[]data=Encoding.ASCII.GetBytes("Thisisatestmessage"); server.SendTo(data,iep); server.Close(); } } NhndliuMulticast classMultiRecv{ publicstaticvoidMain(){ Socketsock=newSocket(AddressFamily.InterNetwork,SocketType.Dgram, ProtocolType.Udp); Console.WriteLine("Readytoreceive"); IPEndPointiep=newIPEndPoint(IPAddress.Any,9050); EndPointep=(EndPoint)iep; sock.Bind(iep); sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, newMulticastOption(IPAddress.Parse("224.100.0.1"))); byte[]data=newbyte[1024]; intrecv=sock.ReceiveFrom(data,refep); stringstringData=Encoding.ASCII.GetString(data,0,recv); Console.WriteLine("received:{0}from:{1}",stringData,ep.ToString()); sock.Close(); } } 51 GidliuMulticastviTTL classNewMultiSend{ publicstaticvoidMain(){ Socketserver=newSocket(AddressFamily.InterNetwork, SocketType.Dgram,ProtocolType.Udp); IPEndPointiep=newIPEndPoint(IPAddress.Any,9051); IPEndPointiep2=newIPEndPoint(IPAddress.Parse("224.100.0.1"),9050); server.Bind(iep); byte[]data=Encoding.ASCII.GetBytes("Thisisatestmessage"); server.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, newMulticastOption(IPAddress.Parse("224.100.0.1"))); server.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive,50); server.SendTo(data,iep2); server.Close(); } }  MulticastvilpUdpClient  JoinMulticastGroup()  DropMulticastGroup()  JoinMulticastGroup()làphươngthcoverload  JoinMulticastGroup(IPAddress)  JoinMulticastGroup(IPAddress,int) classUdpClientMultiSend{ publicstaticvoidMain(){ UdpClientsock=newUdpClient(); IPEndPointiep=newIPEndPoint(IPAddress.Parse("224.100.0.1"),9050); byte[]data=Encoding.ASCII.GetBytes("Thisisatestmessage"); sock.Send(data,data.Length,iep); sock.Close(); } } classUdpClientMultiRecv { publicstaticvoidMain() { UdpClientsock=newUdpClient(9050); Console.WriteLine("Readytoreceive"); sock.JoinMulticastGroup(IPAddress.Parse("224.100.0.1"),50); IPEndPointiep=newIPEndPoint(IPAddress.Any,0); byte[]data=sock.Receive(refiep); stringstringData=Encoding.ASCII.GetString(data,0,data.Length); Console.WriteLine("received:{0}from:{1}",stringData,iep.ToString()); sock.Close(); } } 52 2.7Bàitpápdng classMulticastChat:Form{ TextBoxnewText; ListBoxresults; Socketsock; Threadreceiver; IPEndPointmultiep=newIPEndPoint(IPAddress.Parse("224.100.0.1"),9050); publicMulticastChat(){ Text="MulticastChatProgram"; Size=newSize(400,380); Labellabel1=newLabel(); label1.Parent=this; label1.Text="Entertextstring:"; label1.AutoSize=true; label1.Location=newPoint(10,30); newText=newTextBox(); newText.Parent=this; newText.Size=newSize(200,2*Font.Height); newText.Location=newPoint(10,55); results=newListBox(); results.Parent=this; results.Location=newPoint(10,85); results.Size=newSize(360,18*Font.Height); Buttonsendit=newButton(); sendit.Parent=this; sendit.Text="Send"; sendit.Location=newPoint(220,52); sendit.Size=newSize(5*Font.Height,2*Font.Height); sendit.Click+=newEventHandler(ButtonSendOnClick); Buttoncloseit=newButton(); closeit.Parent=this; closeit.Text="Close"; closeit.Location=newPoint(290,52); closeit.Size=newSize(5*Font.Height,2*Font.Height); closeit.Click+=newEventHandler(ButtonCloseOnClick); sock=newSocket(AddressFamily.InterNetwork,SocketType.Dgram, ProtocolType.Udp); IPEndPointiep=newIPEndPoint(IPAddress.Any,9050); sock.Bind(iep); sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, 53 newMulticastOption(IPAddress.Parse("224.100.0.1"))); receiver=newThread(newThreadStart(packetReceive)); receiver.IsBackground=true; receiver.Start(); } voidButtonSendOnClick(objectobj,EventArgsea){ byte[]message=Encoding.ASCII.GetBytes(newText.Text); newText.Clear(); sock.SendTo(message,SocketFlags.None,multiep); } voidButtonCloseOnClick(objectobj,EventArgsea){ receiver.Abort(); so

Các file đính kèm theo tài liệu này:

  • pdfgiao_trinh_lap_trinh_mang_phan_1.pdf
Tài liệu liên quan