เมื่อเราพูดถึงระบบเครือข่าย เราจะไม่พูดถึงแบบจำลอง OSI ไม่ได้
ในแง่ของโมเดลนี้ วันนี้เราสนใจเลเยอร์การขนส่งมากที่สุด (4)
นี่คือระดับที่เราทำงานกับข้อมูลที่ย้าย "จากจุด A ไปยังจุด B" ภารกิจหลักของเลเยอร์การขนส่งคือเพื่อให้แน่ใจว่าข้อความถูกส่งไปยังปลายทางโดยรักษาลำดับที่ถูกต้องไว้ โปรโตคอลเลเยอร์การขนส่งที่ใช้บ่อยที่สุดคือ TCP และ UDP พวกเขาทำงานตามแนวคิดในรูปแบบต่างๆ กัน แต่แต่ละคนก็มีข้อดีในตัวเองที่ช่วยให้แก้ปัญหาเฉพาะได้
ขั้นแรก เรามาดูว่า TCP ทำงานอย่างไร
TCP (Transmission Control Protocol) เป็นโปรโตคอลเครือข่ายที่รับรองว่ามีการสร้างการเชื่อมต่อระหว่างโฮสต์ก่อนที่จะมีการแลกเปลี่ยนข้อมูล
นี่เป็นโปรโตคอลที่เชื่อถือได้มาก เพราะทุกครั้งที่ส่งแพ็กเก็ตข้อมูลอื่น จะต้องตรวจสอบว่าได้รับแพ็กเก็ตก่อนหน้าหรือไม่
แพ็กเก็ตที่ส่งจะถูกสั่งซื้อ และหากมีปัญหากับแพ็กเก็ตบางแพ็กเก็ต (เช่น ฝ่ายรับไม่ยืนยันว่าแพ็กเก็ตมาถึงแล้ว) แพ็กเก็ตนั้นจะถูกส่งอีกครั้ง เป็นผลให้อัตราการถ่ายโอนค่อนข้างต่ำ เนื่องจากต้องใช้เวลามากขึ้นในการตรวจสอบอย่างเข้มงวดและเพื่อให้แน่ใจว่ามีการสั่งซื้อที่ถูกต้อง
นี่คือที่มาของ "น้องชาย" ซึ่งเป็นโปรโตคอล UDP ซึ่งแตกต่างจาก TCP ตรง UDP ไม่สนใจเกี่ยวกับลำดับและสถานะของแต่ละแพ็กเก็ต เพียงแค่ส่งข้อมูลโดยไม่มีการยืนยันการจัดส่ง ยิ่งไปกว่านั้น มันไม่ได้สร้างการเชื่อมต่อและไม่ได้ขึ้นอยู่กับสถานะการเชื่อมต่อแต่อย่างใด
มีวัตถุประสงค์เพียงเพื่อส่งข้อมูลไปยังที่อยู่ และสิ่งนี้ทำให้โปรโตคอลมีข้อเสียเปรียบหลัก คือ ความน่าเชื่อถือต่ำ เนื่องจากอาจทำให้ข้อมูลบางส่วนสูญหายได้ นอกจากนี้ ผู้รับจะต้องเตรียมพร้อมสำหรับข้อเท็จจริงที่ว่าข้อมูลอาจมาถึงไม่เป็นระเบียบ ที่กล่าวว่าโปรโตคอลยังมีข้อได้เปรียบคืออัตราการถ่ายโอนที่สูงกว่าเนื่องจากโปรโตคอลนั้นจำกัดเฉพาะการส่งข้อมูลเท่านั้น
นอกจากนี้ยังมีความแตกต่างในวิธีการส่งข้อมูล ใน TCP ข้อมูลจะถูกสตรีม ซึ่งหมายความว่าข้อมูลไม่มีขอบเขต ใน UDP ข้อมูลจะถูกส่งเป็นดาตาแกรมและมีขอบเขต และผู้รับจะตรวจสอบความสมบูรณ์ของข้อมูล แต่เฉพาะเมื่อได้รับข้อความสำเร็จเท่านั้น
สรุป:
TCP เป็นโปรโตคอลที่เชื่อถือได้และแม่นยำซึ่งป้องกันข้อมูลสูญหาย ข้อความจะถูกส่งด้วยความแม่นยำสูงสุดเสมอ หรือไม่ได้ส่งเลย ผู้รับไม่ต้องการตรรกะในการสั่งซื้อข้อมูล เนื่องจากข้อมูลขาเข้าจะถูกสั่งซื้อแล้ว | UDP ไม่น่าเชื่อถือ แต่เป็นโปรโตคอลการถ่ายโอนข้อมูลที่เร็วกว่า ฝ่ายส่งและฝ่ายรับต้องการตรรกะเพิ่มเติมเพื่อทำงานกับโปรโตคอลนี้ แต่ลองมาดูวิธีการทำงานโดยใช้ตัวอย่างเกมคอมพิวเตอร์หรือเกมมือถือที่เล่นผ่านเครือข่าย เราอาจไม่สนใจสิ่งที่ควรมาถึงเมื่อ 5 วินาทีที่แล้วอีกต่อไป และเราสามารถข้ามแพ็กเก็ตสองสามแพ็กเก็ตหากมาไม่ทัน — เกมอาจแลค แต่คุณยังสามารถเล่นได้! |
ใน Java ในการทำงานกับดาต้าแกรมที่ส่งผ่าน UDP เราใช้อ็อบเจกต์ของคลาสDatagramSocketและDatagramPacket
ในการแลกเปลี่ยนข้อมูล ผู้ส่งและผู้รับสร้างซ็อกเก็ตดาตาแกรม นั่นคืออินสแตนซ์ของคลาสDatagramSocket คลาสมีตัวสร้างหลายตัว ความแตกต่างระหว่างพวกเขาคือตำแหน่งที่ซ็อกเก็ตที่สร้างขึ้นจะเชื่อมต่อ:
ดาตาแกรมซ็อกเก็ต () | เชื่อมต่อกับพอร์ตที่มีอยู่บนเครื่องโลคัล |
DatagramSocket (พอร์ต int) | เชื่อมต่อกับพอร์ตที่ระบุบนเครื่องภายใน |
DatagramSocket (พอร์ต int, InetAddress addr) | เชื่อมต่อกับพอร์ตที่ระบุที่อยู่บนเครื่องท้องถิ่น (addr) |
คลาสนี้มีวิธีการมากมายในการเข้าถึงและจัดการพารามิเตอร์ซ็อกเก็ต (เราจะดูในภายหลัง) รวมถึงวิธีการรับและส่งดาตาแกรม:
ส่ง (แพ็ค DatagramPacket) | ส่งดาตาแกรมที่บรรจุลงในแพ็กเก็ต |
รับ (แพ็ค DatagramPacket) | รับดาตาแกรมที่บรรจุลงในแพ็กเก็ต |
DatagramPacketเป็นคลาสที่แสดงถึงแพ็คเกจดาตาแกรม แพ็กเก็ต Datagram ใช้เพื่อใช้บริการส่งแพ็กเก็ตแบบไร้การเชื่อมต่อ แต่ละข้อความจะถูกส่งจากเครื่องหนึ่งไปยังอีกเครื่องหนึ่งโดยอิงจากข้อมูลที่มีอยู่ในแพ็คเก็ตนั้นเท่านั้น หลายแพ็กเก็ตที่ส่งจากเครื่องหนึ่งไปยังอีกเครื่องหนึ่งอาจถูกกำหนดเส้นทางแตกต่างกันและอาจมาถึงในลำดับใดก็ได้ ไม่รับประกันการจัดส่งแพ็คเก็ต
คอนสตรัคเตอร์:
DatagramPacket (ไบต์ [] buf ความยาว int) | สร้างDatagramPacketเพื่อยอมรับแพ็กเก็ตที่มีความยาวlength |
DatagramPacket (byte[] buf, ความยาว int, ที่อยู่ InetAddress, พอร์ต int) | สร้างแพ็กเก็ตดาตาแกรมเพื่อส่งแพ็กเก็ตความยาวไปยังหมายเลขพอร์ตที่ระบุบนโฮสต์ที่ระบุ |
DatagramPacket (byte[] buf, int offset, ความยาว int) | สร้างDatagramPacketเพื่อยอมรับแพ็กเก็ตที่มีความยาวlengthโดยระบุออฟเซ็ตในบัฟเฟอร์ |
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) | สร้างแพ็กเก็ตดาตาแกรมเพื่อส่งแพ็กเก็ตความยาวพร้อมออฟเซ็ตออฟเซ็ตไปยังหมายเลขพอร์ตที่ระบุบนโฮสต์ที่ระบุ |
DatagramPacket (byte[] buf, int offset, ความยาว int, ที่อยู่ SocketAddress) | สร้างแพ็กเก็ตดาตาแกรมเพื่อส่งแพ็กเก็ตความยาวพร้อมออฟเซ็ตออฟเซ็ตไปยังหมายเลขพอร์ตที่ระบุบนโฮสต์ที่ระบุ |
DatagramPacket (byte[] buf ความยาว int ที่อยู่ SocketAddress) | สร้างแพ็กเก็ตดาตาแกรมเพื่อส่งแพ็กเก็ตความยาวไปยังหมายเลขพอร์ตที่ระบุบนโฮสต์ที่ระบุ |
เราจำได้ว่าแนวทาง UDP ไม่ได้สร้างการเชื่อมต่อ แพ็กเก็ตจะถูกส่งออกไปด้วยความหวังว่าผู้รับจะคาดหวัง แต่คุณสามารถสร้างการเชื่อมต่อโดยใช้เมธอดconnect(InetAddress addr, int port)ของคลาสDatagramSocket
การเชื่อมต่อทางเดียวถูกสร้างขึ้นกับโฮสต์ตามที่อยู่และพอร์ต: เพื่อส่งหรือรับดาตาแกรม การเชื่อมต่อสามารถยุติได้โดยใช้วิธีการตัดการเชื่อมต่อ ()
ลองเขียนโค้ดเซิร์ฟเวอร์ตามDatagramSocketเพื่อรับข้อมูล:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
class Recipient {
public static void main(String[] args) {
try {
DatagramSocket ds = new DatagramSocket(1050);
while (true) {
DatagramPacket pack = new DatagramPacket(new byte[5], 5);
ds.receive(pack);
System.out.println(new String(pack.getData()));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
เราสร้าง วัตถุ DatagramSocketเพื่อฟังบนพอร์ต 1050 เมื่อได้รับข้อความ จะพิมพ์ไปยังคอนโซล เราจะส่งคำว่า "สวัสดี" ดังนั้นเราจึงจำกัดขนาดบัฟเฟอร์ไว้ที่ห้าไบต์
ตอนนี้เราจะสร้างคลาสผู้ส่ง:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
class Sender {
private String host;
private int port;
Sender(String host, int port) {
this.host = host;
this.port = port;
}
private void sendMessage(String mes) {
try {
byte[] data = mes.getBytes();
InetAddress address = InetAddress.getByName(host);
DatagramPacket pack = new DatagramPacket(data, data.length, address, port);
DatagramSocket ds = new DatagramSocket();
ds.send(pack);
ds.close();
} catch (IOException e) {
System.err.println(e);
}
}
public static void main(String[] args) {
Sender sender = new Sender("localhost", 1050);
String message = "Hello";
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
sender.sendMessage(message);
}
}, 1000, 1000);
}
}
ใน เมธอด sendMessageเราสร้างDatagramPacketและDatagramSocketและส่งข้อความของเรา โปรดทราบว่า เมธอด close()ใช้เพื่อปิดDatagramSocketหลังจากส่งข้อความ
ทุกวินาทีคอนโซลของผู้รับจะแสดงข้อความ "สวัสดี" ขาเข้าที่ส่งโดยผู้ส่ง ซึ่งหมายความว่าการสื่อสารของเราทำงานได้อย่างถูกต้อง
GO TO FULL VERSION