簡(jiǎn)單認(rèn)識(shí)一下傳輸層中的UDP和TCP:
TCP:有鏈接,可靠傳輸,面向字節(jié)流,全雙工
UDP:無(wú)連接,不可靠傳輸,面向數(shù)據(jù)報(bào),全雙工
有鏈接類似于打電話,通了就是有鏈接。沒(méi)通就一直在等待。
無(wú)連接類似于發(fā)短信,只管發(fā),不管到。
可靠傳輸就是保證信息傳輸?shù)目煽啃?。就好比打電話時(shí),你會(huì)詢問(wèn)對(duì)方在嗎,對(duì)方回復(fù)你,你在發(fā)送重要數(shù)據(jù)給對(duì)方。不可靠傳輸,就好比發(fā)短信。假設(shè)對(duì)方開(kāi)啟了飛行模式,你短信依然能發(fā),但是對(duì)方收不收得到,你并不關(guān)心也不會(huì)詢問(wèn)。
字節(jié)流:能按需所取,比如100個(gè)字節(jié),可以一個(gè)字節(jié)一個(gè)字節(jié)取100次,也能5個(gè)字節(jié)5個(gè)字節(jié)的讀20次。
數(shù)據(jù)報(bào):固定的字節(jié)數(shù)據(jù)構(gòu)成一個(gè)數(shù)據(jù)報(bào),一次只能讀取發(fā)送一個(gè)數(shù)據(jù)報(bào)。
全雙工就是雙向通信。既能發(fā)送也能接收的意思。
簡(jiǎn)單介紹了TCP,UDP的一些特性,下面我們來(lái)看Java中兩個(gè)重要的網(wǎng)絡(luò)編程的類。
DatagramSocket這個(gè)類提供了兩個(gè)構(gòu)造方法:
一個(gè)是無(wú)參構(gòu)造方法,相當(dāng)于只是創(chuàng)建了一個(gè)socket,另外一個(gè)需要傳入一個(gè)端口號(hào)。?此時(shí)就是讓當(dāng)前的socket對(duì)象和這個(gè)指定的端口,關(guān)聯(lián)起來(lái)。無(wú)參構(gòu)造也會(huì)分配一個(gè)端口號(hào),不過(guò)是系統(tǒng)自動(dòng)分配空閑的端口號(hào)。
?這兩個(gè)方法的參數(shù)是一個(gè)DatagaramPacket.這也是一個(gè)類,先來(lái)介紹下:
用于釋放資源的。
DatagramPacket這個(gè)類也提供了2個(gè)構(gòu)造方法:
?第一個(gè)構(gòu)造方法相當(dāng)于設(shè)置好了一個(gè)緩沖區(qū)。
第二個(gè)構(gòu)造方法既構(gòu)造了一個(gè)緩沖區(qū)又構(gòu)造了一個(gè)地址。
基于這兩個(gè)API,構(gòu)造一個(gè)最簡(jiǎn)單的UDP客戶端服務(wù)器程序。
?服務(wù)器端的代碼:
package network;
//Udp回顯的服務(wù)器
import javax.imageio.IIOException;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class UdpEchoServer {
//網(wǎng)絡(luò)編程的本質(zhì)是要操作網(wǎng)卡
//網(wǎng)卡不好直接操作,因此操作系統(tǒng)把socket這樣的文件抽象成了網(wǎng)卡
//因此進(jìn)行網(wǎng)絡(luò)通信,勢(shì)必先有一個(gè)socket對(duì)象。
private DatagramSocket socket=null;
//對(duì)于服務(wù)器來(lái)說(shuō),創(chuàng)建socket對(duì)象的同時(shí),要讓他綁定上一個(gè)具體的端口號(hào)
public UdpEchoServer(int port) throws SocketException {
socket =new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("服務(wù)器啟動(dòng)??!");
while (true){
//并不知道有多少個(gè)客戶端想建立鏈接,因此寫(xiě)個(gè)循環(huán)
//只要有客戶端過(guò)來(lái),就可以提供服務(wù)
//1.讀取客戶端發(fā)來(lái)的請(qǐng)求是啥
//receive方法,需要一個(gè)空白DatagramPacket對(duì)象,交給receive來(lái)進(jìn)行填充。填充的數(shù)據(jù)來(lái)自于網(wǎng)卡
DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
socket.receive(requestPacket);
//此時(shí)這個(gè)DatagramPacket是一個(gè)特殊的對(duì)象,并不方便直接處理,可以把這里包含的數(shù)據(jù)拿出來(lái),構(gòu)成一個(gè)字符串
String request=new String(requestPacket.getData(),0,requestPacket.getLength());
//2.根據(jù)請(qǐng)求計(jì)算響應(yīng),由于此處是回顯服務(wù)器,響應(yīng)和請(qǐng)求相同。
String response=process(request);
//3.把回顯寫(xiě)回到客戶端,send參數(shù)也是DatagramPacket 需要把這個(gè)Packet對(duì)象構(gòu)造好
DatagramPacket responsePacket =new DatagramPacket(response.getBytes(),response.getBytes().length,
requestPacket.getSocketAddress());
socket.send(responsePacket);
//4.打印請(qǐng)求響應(yīng)的處理中間結(jié)果
System.out.printf("[%s:%d] req: %s; resp:%s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),
request,response);
}
}
//這個(gè)方法表示根據(jù)請(qǐng)求計(jì)算響應(yīng)
public String process(String request){
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoServer server=new UdpEchoServer(9090);
server.start();
}
}
這里我們用while循環(huán)實(shí)現(xiàn)了一直等待客戶端發(fā)送請(qǐng)求這么一個(gè)過(guò)程。假設(shè)客戶端不停的發(fā)送請(qǐng)求,并且請(qǐng)求的頻率非???。我這個(gè)服務(wù)器是否就忙不過(guò)來(lái)處理了呢?這個(gè)情況是很可能出現(xiàn)的。那么解決的方法就是高并發(fā)執(zhí)行。好比我開(kāi)了一家餐館,生意不好的時(shí)候,我一個(gè)人綽綽有余。但是生意非常好。我一個(gè)人忙不過(guò)來(lái),這個(gè)時(shí)候我雇了2個(gè)人來(lái)幫忙。這就是高并發(fā)的原理。那么高并發(fā)是如何實(shí)現(xiàn)呢。那就是通過(guò)多線程實(shí)現(xiàn)。一個(gè)核心一個(gè)線程的并發(fā)執(zhí)行。效率就會(huì)高很多。但是硬件設(shè)施終有上限。那么通過(guò)加機(jī)器也就就解決這個(gè)硬件問(wèn)題了。
客戶端的代碼:
package network;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
//Udp回顯客戶端
public class UdpEchoClient {
private DatagramSocket socket=null;
private String serverIp=null;
private int serverPort=0;
public UdpEchoClient (String serverIp,int serverPort) throws SocketException {
socket =new DatagramSocket();
this.serverIp=serverIp;
this.serverPort=serverPort;
}
public void start()throws IOException {
System.out.println("客戶端啟動(dòng)!");
Scanner scanner=new Scanner(System.in);
while (true) {
//1.從控制臺(tái)讀取要發(fā)送的數(shù)據(jù)
System.out.print("> ");
String request =scanner.next();
if(request.equals("exit")){
System.out.println("goodbye");
break;
}
//2.構(gòu)造成UDP請(qǐng)求,并發(fā)送,構(gòu)造這個(gè)Packet的時(shí)候,需要傳入serverIp和port,此處的IP地址是需要一個(gè)32位的整數(shù)形式
//而上述的IP是一個(gè)字符串,所以需要進(jìn)行轉(zhuǎn)換
DatagramPacket requestPacket =new DatagramPacket(request.getBytes(),request.getBytes().length,
InetAddress.getByName(serverIp),serverPort);
socket.send(requestPacket);
//3.讀取服務(wù)器的UDP請(qǐng)求,并解析
DatagramPacket responsePacket =new DatagramPacket(new byte[4096],4096);
socket.receive(responsePacket);
String response =new String(responsePacket.getData(),0,responsePacket.getLength());
//4.解析結(jié)果顯示出來(lái)
System.out.println(response);
}
}
public static void main(String[] args) throws IOException{
UdpEchoClient client =new UdpEchoClient("127.0.0.1",9090);
client.start();
}
}
首先啟動(dòng)我們的服務(wù)器:
就會(huì)進(jìn)入等待請(qǐng)求的狀態(tài)。
再啟動(dòng)服務(wù)器:
?我們輸入一個(gè)hello;
?服務(wù)器就會(huì)給我們回一個(gè)hello。我們?cè)倏捶?wù)器那邊:
收到了客戶端的的IP地址端口號(hào)。以上就是實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的回顯服務(wù)器和客戶端。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-508785.html
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-508785.html
到了這里,關(guān)于計(jì)算機(jī)網(wǎng)絡(luò)--網(wǎng)絡(luò)編程(1)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!