1. บทนำสู่ TCP/IP
ตระกูลโปรโตคอล TCP/IP เป็นโปรโตคอลที่ใช้โดยอินเทอร์เน็ตและยังสามารถใช้ในเครือข่ายส่วนตัวอิสระ
ตระกูลโปรโตคอล TCP/IP รวมถึงโปรโตคอล IP, โปรโตคอล TCP และโปรโตคอล UDP
โปรโตคอล IP ใช้ที่อยู่ IP เพื่อแจกจ่ายแพ็คเก็ต แต่เป็นบริการที่ดีที่สุดและแพ็คเก็ตอาจหายไปตามคำสั่งหรือทำซ้ำ โปรโตคอล TCP และ UDP เพิ่มหมายเลขพอร์ตลงในโปรโตคอล IP ซึ่งจะสร้างการเชื่อมต่อที่โปร่งใสระหว่างแอปพลิเคชันของโฮสต์ทั้งสอง
ความแตกต่างคือโปรโตคอล TCP แก้ไขข้อผิดพลาดเลเยอร์ IP ซึ่งสร้างการเชื่อมต่อระหว่างโฮสต์ผ่านข้อความจับมือกัน
จากนั้นข้อผิดพลาดในข้อความจะถูกกู้คืนโดยการเพิ่มหมายเลขซีเรียลลงในข้อความ UDP เพียงแค่ขยายโปรโตคอล IP
เปิดใช้งานการทำงานระหว่างแอปพลิเคชันไม่ใช่ระหว่างโฮสต์
เกี่ยวกับที่อยู่ IP โฮสต์สามารถมีอินเทอร์เฟซเครือข่ายหลายตัวและอินเทอร์เฟซหนึ่งสามารถมีที่อยู่ได้หลายที่
ที่อยู่ IP บางแห่งมีการใช้งานพิเศษ:
A. ที่อยู่ loopback: 127.0.0.1, ถูกกำหนดให้กับอินเตอร์เฟส loopback เสมอส่วนใหญ่ใช้สำหรับการทดสอบ
B. ที่อยู่ส่วนตัว: เริ่มต้นด้วย 10, 192.168, 172. (16-31), ใช้สำหรับเครือข่ายส่วนตัว เมื่ออุปกรณ์ NAT ส่งต่อข้อความมันจะแมปพอร์ตที่อยู่ส่วนตัวของข้อความในอินเทอร์เฟซเดียวในพอร์ตที่อยู่สาธารณะในอินเทอร์เฟซอื่น สิ่งนี้ช่วยให้กลุ่มโฮสต์กลุ่มเล็ก ๆ สามารถแชร์คู่ที่อยู่ IP ได้
C. ที่อยู่ Multicast: หมายเลขแรกอยู่ระหว่าง 224 และ 239
2. ซ็อกเก็ตพื้นฐาน
1. ได้รับที่อยู่
โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ลอง {การแจงนับ <netorthInterface> interfaces = networkInterface.getNetWorkInterfaces (); ในขณะที่ (interfaces.hasmoreElements ()) {networkInterface iface = interfaces.nextElement (); System.out.println ("อินเตอร์เฟส:" + iface.getName ()); การแจงนับ <NetAddress> addrlist = iface.getInetAddresses (); if (! addrlist.hasmoreElements ()) System.out.println ("ไม่มีที่อยู่"); ในขณะที่ (addrlist.hasmoreElements ()) {ที่อยู่ inetAddress = addrlist.nextElement (); System.out.println ("ที่อยู่:" + address.getHostaddress ()); }}} catch (socketexception e) {e.printstacktrace (); -2. โปรแกรมอินสแตนซ์ TCP
ควรสังเกตว่าแม้ว่าจะใช้วิธีการเขียนเพียงครั้งเดียว () เพื่อส่งสตริงทางฝั่งไคลเอ็นต์ แต่ฝั่งเซิร์ฟเวอร์อาจได้รับข้อมูลนี้จากหลายบล็อก แม้ว่าสตริงข้อเสนอแนะจะถูกเก็บไว้ในบล็อกเมื่อเซิร์ฟเวอร์ส่งคืนมันอาจเป็น TCP
โปรโตคอลแบ่งออกเป็นหลายส่วน
tcpechoclienttest.java
โมฆะคงที่สาธารณะหลัก (String [] args) พ่น IOException {String Server = args [0]; ไบต์ [] data = args [1] .getBytes (); พอร์ต int = 7; ซ็อกเก็ตซ็อกเก็ต = ซ็อกเก็ตใหม่ (เซิร์ฟเวอร์พอร์ต); System.out.println ("เชื่อมต่อกับเซิร์ฟเวอร์ ... "); inputStream ใน = socket.getInputStream (); outputStream out = socket.getOutputStream (); out.write (ข้อมูล); int totalByTesRcvd = 0; int bytesrcvd; ในขณะที่ (TotalByTesRcvd <data.length) {ถ้า ((bytesrcvd = in.read (data, totalByTesRcvd, data.length - TotalByTesRcvd)) == -1) โยน socketexception ใหม่ ("ปิดการเชื่อมต่อ"); TotalByTesRcvd += bytesrcvd; } system.out.println ("ได้รับ:" + สตริงใหม่ (ข้อมูล)); Socket.close (); -tcpechoservertest.java
ส่วนตัวคงที่ int bufsize = 32; โมฆะสาธารณะคงที่หลัก (สตริง [] args) พ่น IOException {Serversocket serversocket = Serversocket ใหม่ (7); int recvmsgsize; ไบต์ [] รับ buf = ไบต์ใหม่ [bufsize]; ในขณะที่ (จริง) {ซ็อกเก็ตซ็อกเก็ต = serversocket.accept (); System.out.println ("การจัดการไคลเอนต์" + "จากระยะไกล" + socket.getRemotesocketAddress () + "ที่ท้องถิ่น" + socket.getLocalsocketAddress ()); inputStream ใน = socket.getInputStream (); outputStream out = socket.getOutputStream (); ในขณะที่ ((recvmsgsize = in.read (รับ buf))! = -1) {out.write (รับ buf, 0, recvmsgsize); } socket.close (); -โปรดทราบว่าซ็อกเก็ตใหม่ระบุหมายเลขพอร์ตที่เซิร์ฟเวอร์ระยะไกลฟังโดยไม่ระบุพอร์ตท้องถิ่นดังนั้นจะใช้ที่อยู่เริ่มต้นและหมายเลขพอร์ตที่มีอยู่ บนพอร์ตไคลเอนต์เครื่องของฉันคือ 4593 เชื่อมต่อกับพอร์ต 7 ของเซิร์ฟเวอร์
3. โปรแกรมอินสแตนซ์ UDP
ทำไมต้องใช้โปรโตคอล UDP? หากแอปพลิเคชันแลกเปลี่ยนข้อมูลเพียงเล็กน้อยขั้นตอนการจัดตั้งของการเชื่อมต่อ TCP จะส่งข้อมูลอย่างน้อยสองเท่า (และเวลาเดินทางไปกลับสองครั้ง)
Udpechoclienttest.java
โมฆะคงที่สาธารณะหลัก (String [] args) พ่น IOException {Inetaddress serveraddress = inetaddress.getByName (args [0]); ไบต์ [] bytestosend = args [1] .getBytes (); DataGramSocket Socket = ใหม่ DataGramSocket (); Socket.setSotimeout (3000); DataGrampacket sendPacket = DataGampacket ใหม่ (bytestosend, bytestosend.length, ServerAddress, 7); DataGampacket รับ packet = ใหม่ DataGampacket (BYTE ใหม่ [bytestosend.length], bytestosend.length); // แพ็คเก็ตอาจหายไปดังนั้นเราต้องพยายามพยายามอย่างต่อเนื่อง = 0; Boolean ได้รับ Response = FALSE; ทำ {socket.send (sendpacket); ลอง {socket.receive (รับแพ็คเก็ต); if (! teedpacket.getAddress (). เท่ากับ (serveraddress)) โยน iOexception ใหม่ ("รับจากแหล่งที่ไม่รู้จัก"); ได้รับ Response = true; } catch (ioexception e) {พยายาม ++; System.out.println ("หมดเวลาลองอีกครั้ง"); }} ในขณะที่ (! ได้รับการตอบสนอง && พยายาม <5); ถ้า (ได้รับการตอบสนอง) System.out.println ("ได้รับ:" + สตริงใหม่ (teedpacket.getData ())); อื่น System.out.println ("ไม่มีการตอบสนอง"); Socket.close (); - Udpechoservertest.java
echomax int สุดท้ายส่วนตัว = 255; โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น IOException {datagramsocket socket = dataGramsocket ใหม่ (7); DataGrampacket Packet = DataGampacket ใหม่ (BYTE ใหม่ [ECHOMAX], ECHOMAX); ในขณะที่ (จริง) {socket.receive (แพ็คเก็ต); System.out.println ("การจัดการไคลเอนต์ที่" + packet.getAddress ()); Socket.Send (แพ็คเก็ต); packet.setLength (eChomax); -การเปรียบเทียบตัวอย่างนี้กับอินสแตนซ์ TCP ก่อนหน้านี้มีความแตกต่างต่อไปนี้:
A.Datagramsocket ไม่จำเป็นต้องระบุที่อยู่ปลายทางเมื่อสร้างขึ้นเนื่องจาก UDP ไม่จำเป็นต้องสร้างการเชื่อมต่อและแต่ละแพ็กเก็ตข้อมูลสามารถส่งหรือรับจากที่อยู่ปลายทางอื่น
B. หากคุณบล็อกและรออ่าน () เช่น TCP มันอาจถูกบล็อกที่นั่นตลอดไปเพราะโปรโตคอล UDP ขยายโปรโตคอล IP และแพ็คเก็ต UDP อาจหายไป ดังนั้นคุณต้องตั้งเวลาหมดเวลาสำหรับการปิดกั้นการรอคอย
C.UDP Protocol เก็บข้อมูลขอบเขตของข้อความและการโทร () การโทร () แต่ละรายการสามารถรับข้อมูลที่ส่งโดยการโทร () การโทรเพียงครั้งเดียว
D. ข้อมูลสูงสุดที่แพ็คเก็ต UDP สามารถส่งได้คือ 65507 ไบต์ ไบต์ส่วนเกินจะถูกยกเลิกโดยอัตโนมัติและไม่มีการแจ้งเตือนสำหรับโปรแกรมรับ ดังนั้นจึงปลอดภัยที่จะตั้งค่าอาร์เรย์แคชเป็นประมาณ 65,000 ไบต์
E. หากวิธีการรับ () ถูกเรียกซ้ำ ๆ ด้วยอินสแตนซ์ DataGampacket เดียวกันความยาวภายในของข้อความจะต้องรีเซ็ตเป็นความยาวจริงของแคชอย่างชัดเจนก่อนการโทรแต่ละครั้ง