目錄
1.網(wǎng)絡(luò)編程的基本概念
1.1為什么需要網(wǎng)絡(luò)編程?
1.2服務(wù)端與用戶端
1.3網(wǎng)絡(luò)編程五元組?
1.4套接字的概念
2.UDP套接字編程
2.1UDP套接字的特點(diǎn)
?2.2UDP套接字API
2.2.1DatagramSocket類
2.2.2DatagramPacket類?
2.2.3基于UDP的回顯程序
2.2.4基于UDP的單詞查詢?
3.TCP套接字編程
3.1TCP套接字的特點(diǎn)
3.2TCP中的長短連接
3.3TCP套接字的API
3.3.2Socket類
3.3.3基于TCP的回顯程序
3.3.4對TCP回顯程序的優(yōu)化
1.網(wǎng)絡(luò)編程的基本概念
網(wǎng)絡(luò)編程,指網(wǎng)絡(luò)上的主機(jī),通過不同的進(jìn)程,以編程的方式實(shí)現(xiàn)網(wǎng)絡(luò)通信(或稱為網(wǎng)絡(luò)數(shù)據(jù)傳輸)。對于我們程序員來說,我們比較關(guān)注應(yīng)用層到傳輸層這一操作,我們代碼的書寫是發(fā)生在應(yīng)用層的,然后通過傳輸層提供的API(UDP和TCP)進(jìn)行包裝,再由應(yīng)用層發(fā)送給傳輸層。
1.1為什么需要網(wǎng)絡(luò)編程?
?這個最為直接的說話莫過于人民需要他了,哪里有需求,哪里就提供響應(yīng)嘛。
相比于本地的資源,網(wǎng)絡(luò)上有這更為豐富的資源,而網(wǎng)絡(luò)上的資源又需要通過網(wǎng)絡(luò)編程來上傳,因此就相互督促相互促進(jìn)了對方的發(fā)展。
1.2服務(wù)端與用戶端
服務(wù)端:在常見的網(wǎng)絡(luò)數(shù)據(jù)傳輸場景下,把提供服務(wù)的一方進(jìn)程,稱為服務(wù)端,可以提供對外服務(wù)。
客戶端:獲取服務(wù)的一方進(jìn)程,稱為客戶端。
簡單的說,客戶端會接收到客戶的請求,再將客戶的請求發(fā)送給服務(wù)端;服務(wù)端將請求按照業(yè)務(wù)邏輯完成響應(yīng),再將響應(yīng)返回給客戶端,客戶端再將響應(yīng)按照操作顯示或者運(yùn)作。
1.3網(wǎng)絡(luò)編程五元組?
- 源IP:就是發(fā)送方IP.
- 源端口:發(fā)送方端口號, 服務(wù)器需要手動指定, 客戶端讓系統(tǒng)隨機(jī)分配即可.
- 目的IP: 接收方IP, 包含在拿到的數(shù)據(jù)報中, 服務(wù)器響應(yīng)時的目的IP就在客戶端發(fā)來的數(shù)據(jù)報中, 客戶端發(fā)送請求時的目的IP就是服務(wù)器的IP.
- 目的端口: 接收方端口號包含在數(shù)據(jù)報中, 服務(wù)器響應(yīng)時的目的端口就在客戶端發(fā)來的數(shù)據(jù)報中, 客戶端發(fā)送請求時的目的端口就是服務(wù)器的端口號.
- 協(xié)議類型:如UDP/TCP.
1.4套接字的概念
Socket(套接字)可以看成是兩個網(wǎng)絡(luò)應(yīng)用程序進(jìn)行通信時,各自通信連接中的端點(diǎn),這是一個邏輯上的概念。Socket是由IP地址和端口結(jié)合的,提供向應(yīng)用層進(jìn)程傳送數(shù)據(jù)包的機(jī)制?
套接字的表示方法:Socket=Ip接口:端口號
2.UDP套接字編程
2.1UDP套接字的特點(diǎn)
特點(diǎn)如下:
- 無連接:不關(guān)心和誰對話,也不會刻意留意對方。
- 不可靠的:不關(guān)心他收沒收到。
- 面向數(shù)據(jù)報:以一個UDP數(shù)據(jù)報為單位。
- 全雙工通信:一條路徑,但是路徑兩方都可以對話。(雙向?qū)υ挘?/li>
?2.2UDP套接字API
UDP套接字的API中主要包括兩個類?:1.DatagramSocket 2.DatagramPacket。
下面就開始介紹這兩個類
2.2.1DatagramSocket類
?DatagramSocket類就是實(shí)例一個UDP版本的套接字也是就數(shù)據(jù)包套接字。Socket對象對應(yīng)到系統(tǒng)中的一個特殊文件(socket文件),socket文件不是數(shù)據(jù)存儲區(qū)域的一部分,而是對應(yīng)到網(wǎng)卡這個硬件設(shè)備,為什么對應(yīng)到網(wǎng)卡呢?因?yàn)榫W(wǎng)卡是一個硬件,對于代碼而已,不好直接操作,因此將它抽象成了一個文件進(jìn)行間接操作。
DatagramSocket類構(gòu)造方法:
方法簽名 | 方法說明 |
---|---|
DatagramSocket() | 創(chuàng)建一個UDP數(shù)據(jù)報套接字的Socket,綁定到本機(jī)任意一個隨機(jī)端口 (一般用于客戶端) |
DatagramSocket(int port) |
創(chuàng)建一個UDP數(shù)據(jù)報套接字的Socket,綁定到本機(jī)指定的端口(一般用 于服務(wù)端) |
我們一般使用第二個方法,我們知道端口號是在一個計算機(jī)中尋找一個程序的“門牌號”。實(shí)際操作時,如果端口號是系統(tǒng)隨機(jī)綁定的話,我們就不知道我們服務(wù)端服務(wù)于哪一個客戶端了,就沒有辦法找到客戶端的家了。
DatagramSocket類方法:
方法簽名 | 方法說明 |
---|---|
void receive(DatagramPacket p) |
從此套接字接收數(shù)據(jù)報(如果沒有接收到數(shù)據(jù)報,該方法會阻 塞等待) |
void send(DatagramPacket p) |
從此套接字發(fā)送數(shù)據(jù)報包(不會阻塞等待,直接發(fā)送) |
void close() | 關(guān)閉此數(shù)據(jù)報套接字 |
第一個receive方法它的參數(shù)需要準(zhǔn)備一個空的DatagramPacket對象(對象需要給予存儲空間),它把DatagramPacket實(shí)例對象再裝入到準(zhǔn)備好的空的DatagramPacket對象中去 ,為什么這樣做呢?就像我們平常接收東西時,我們需要一個載體來承接這個物件,舉個例子吧,當(dāng)我們盛飯時,我們不能夠直接用手去捧著飯,而是需要一個空飯盒去接打的飯。
第二個send方法他是DatagramPacket實(shí)例對象載入到接收緩沖區(qū)。
第三個close方法,因?yàn)镈atagramSocket類屬于文件資源,當(dāng)我們不用的時候,我們需要將它給手動關(guān)閉了。
2.2.2DatagramPacket類?
DatagramPacket是UDP Socket發(fā)送和接收的數(shù)據(jù)報。?
DatagramPacket類構(gòu)造方法
方法簽名 | 方法說明 |
---|---|
DatagramPacket(byte[] buf, int length) |
構(gòu)造一個DatagramPacket以用來接收數(shù)據(jù)報,接收的數(shù)據(jù)保存在 字節(jié)數(shù)組(第一個參數(shù)buf)中,接收指定長度(第二個參數(shù) length) |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) |
構(gòu)造一個DatagramPacket以用來發(fā)送數(shù)據(jù)報,發(fā)送的數(shù)據(jù)為字節(jié) 數(shù)組(第一個參數(shù)buf)中,從0到指定長度(第二個參數(shù) length)。address指定目的主機(jī)的IP和端口號 |
這兩個構(gòu)造方法都會使用到,第一個構(gòu)造方法:他就是我們上方說的空的DatagramPacket對象也就是我們舉例說的“空飯盒”,第二個構(gòu)造方法是在我們將接收到的請求進(jìn)行封裝時使用的,假設(shè)我們接收到的請求是字符串,我們就要將它轉(zhuǎn)化成byte數(shù)組,再算出長度,并且需要指定它要發(fā)送到那里去也就是SockerAddress類的一個子類InetSocketAddress類它里面包含目的ip和目的端口號。
DatagramPacket類方法:
方法簽名 | 方法說明 |
---|---|
InetAddress getAddress() |
從接收的數(shù)據(jù)報中,獲取發(fā)送端主機(jī)IP地址;或從發(fā)送的數(shù)據(jù)報中,獲取 接收端主機(jī)IP地址 |
int getPort() | 從接收的數(shù)據(jù)報中,獲取發(fā)送端主機(jī)的端口號;或從發(fā)送的數(shù)據(jù)報中,獲 取接收端主機(jī)端口號 |
byte[] getData() | 獲取數(shù)據(jù)報中的數(shù)據(jù) |
2.2.3基于UDP的回顯程序
UDP服務(wù)端:
服務(wù)器設(shè)計邏輯:?
- ?創(chuàng)建DatagramSocket對象,指定服務(wù)器端口號。
- 服務(wù)器啟動了,我們需要一個DatagramPacket實(shí)例運(yùn)來當(dāng)作載體,當(dāng)沒有請求時,在這里就會發(fā)生阻塞,有請求時,就寫入到DatagramPacket實(shí)例好的載體中。
- 接收到數(shù)據(jù)后,我們將數(shù)據(jù)拆分成我們需要的格式,因?yàn)槲覀兪且粋€回顯,故我們只需將它改成字符串就行了,再調(diào)用process方法,在這里完成業(yè)務(wù)需求,我們這里只需返回字符串就像了。
- 將處理好的請求,再封裝一下,封裝成DatagramPacket實(shí)例對象,將這個響應(yīng)發(fā)生使用send方法發(fā)送給客戶端即可。
package UdpNetWork;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
//服務(wù)器端
public class UdpEchoServer {
private DatagramSocket socket=null;
public UdpEchoServer(int port) throws SocketException {
this.socket=new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("服務(wù)器啟動");
while (true) {
//requestPacket是一個載體,receive方法會將發(fā)送過來的數(shù)據(jù)放入到這個載體中
DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
socket.receive(requestPacket);
//將發(fā)來的數(shù)據(jù)拆解
String request=new String(requestPacket.getData(),0, requestPacket.getLength());
//做出響應(yīng)
String response=process(request);
//將做出的響應(yīng)包裝起來,發(fā)給客戶端
DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,
requestPacket.getSocketAddress());
socket.send(responsePacket);
//打印日志
System.out.printf("[%s:%d] req:%s,resp:%s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),
request,response);
}
}
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoServer udpEchoServer=new UdpEchoServer(9090);
udpEchoServer.start();
}
}
?UDP客戶端:
?客戶端設(shè)計邏輯:
- ?客戶端需要知道服務(wù)端的位置,因此我們需要服務(wù)端的ip地址和端口號,故成員變量包含Ipserver、serverPort以及一個DatagramSocket對象(可以理解為整合ip和端口號)。
- 開始運(yùn)行客戶端,通過Scaner接收客戶的請求。
- 拿到請求后,我們需要將它封裝成DatagramPacket對象,發(fā)送給服務(wù)端。
- 發(fā)送完就等待服務(wù)端返回響應(yīng)。
- 等到拿到響應(yīng)之后,我們就可以對響應(yīng)做出操作了,因?yàn)槲覀冞@里是回顯,我們只需將返回過來的字符串打印出來即可。
package UdpNetWork;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;
//客戶端
public class UdpEchoClient {
private DatagramSocket socket=null;
private int serverPort;
private String IpServer;
public UdpEchoClient(int port, String ipServer) throws SocketException {
socket=new DatagramSocket();
this.serverPort=port;
this.IpServer=ipServer;
}
public void start() throws IOException {
Scanner sc=new Scanner(System.in);
while (true) {
System.out.print("輸入字符->");
String request=sc.next();
//將輸入的指令打包
DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
InetAddress.getByName(IpServer),serverPort);
//發(fā)送給服務(wù)器端
socket.send(requestPacket);
DatagramPacket responsePacket=new DatagramPacket(new byte[4096], 4096);
//接收服務(wù)器端的響應(yīng)結(jié)果
socket.receive(responsePacket);
//打印服務(wù)端的響應(yīng)
String response=new String(responsePacket.getData(),0,responsePacket.getLength());
//打印日志
System.out.printf("req:%s,resp:%s\n",request,response);
}
}
public static void main(String[] args) throws IOException {
UdpEchoClient udpEchoClient=new UdpEchoClient(9090,"127.0.0.1");
udpEchoClient.start();
}
}
2.2.4基于UDP的單詞查詢?
對于這個服務(wù)端,我們不需要再寫一邊start方法了,我們可以直接讓它繼承udpEchoServer類,并且,我們在上方服務(wù)端,我們將對請求處理的部分拿出來當(dāng)作了一個單獨(dú)的函數(shù),我們在將上方的函數(shù)進(jìn)行重寫就行了,還有就是,我們需要一個存儲單詞,并且它還方便查詢的東西,我們就想到一個數(shù)據(jù)結(jié)構(gòu)就是Map,剛好可以適合這個系統(tǒng)。
package UdpNetWork;
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
public class UdpDictServer extends UdpEchoServer{
//字典表
private Map<String, String> dict = new HashMap<>();
public UdpDictServer(int port) throws SocketException {
super(port);
dict.put("dog", "小狗");
dict.put("cat", "小貓");
dict.put("fuck", "臥槽");
// ........... 可以無限的添加很多很多數(shù)據(jù). 有道詞典和咱們相比, 就是人家的這個表更大!!
}
@Override
public String process(String request) {
return dict.getOrDefault(request, "該單詞沒有查到!");
}
public static void main(String[] args) throws IOException {
UdpDictServer udpDictServer = new UdpDictServer(9090);
udpDictServer.start();
}
}
3.TCP套接字編程
3.1TCP套接字的特點(diǎn)
特點(diǎn)如下:
- 有鏈接:雙方通信,都需要可以留意對方信息。
- 可靠傳輸:盡可能的將數(shù)據(jù)傳輸給對方,但也不能保證100%。
- 面向字節(jié)流:以一個字節(jié)傳輸為基本單位。
- 全雙工:雙方都可以向?qū)Ψ桨l(fā)送信息。
3.2TCP中的長短連接
TCP發(fā)送數(shù)據(jù)時,需要先建立連接,什么時候關(guān)閉連接就決定是短連接還是長連接:
短連接:每次接收到數(shù)據(jù)并返回響應(yīng)后,都關(guān)閉連接,即是短連接。也就是說,短連接只能一次收發(fā)數(shù)據(jù)。
長連接:不關(guān)閉連接,一直保持連接狀態(tài),雙方不停的收發(fā)數(shù)據(jù),即是長連接。也就是說,長連接可以多次收發(fā)數(shù)據(jù)。
長連接與短鏈接的區(qū)別:
- 建立連接、關(guān)閉連接的耗時:短連接每次請求、響應(yīng)都需要建立連接,關(guān)閉連接;而長連接只需要第一次建立連接,之后的請求、響應(yīng)都可以直接傳輸。相對來說建立連接,關(guān)閉連接也是要耗時的,長連接效率更高。
- 主動發(fā)送請求不同:短連接一般是客戶端主動向服務(wù)端發(fā)送請求;而長連接可以是客戶端主動發(fā)送請求,也可以是服務(wù)端主動發(fā)。
- 兩者的使用場景有不同:短連接適用于客戶端請求頻率不高的場景,如瀏覽網(wǎng)頁等。長連接適用于客戶端與服務(wù)端通信頻繁的場景,如聊天室,實(shí)時游戲等。
3.3TCP套接字的API
TCP套接字的API中主要包含兩個類:1.ServerSocket 2.Socket
下面介紹這兩個類
3.3.1ServerSocket類
這個類是在看名字就很好理解,它主要用于服務(wù)端,它的作用是創(chuàng)建一個服務(wù)端套接字。
?ServerSocket類構(gòu)造方法:
方法簽名 | 方法說明 |
---|---|
ServerSocket(int port) | 創(chuàng)建一個服務(wù)端流套接字Socket,并綁定到指定端口 |
在實(shí)例對象時,我們就將端口號傳進(jìn)來,完成實(shí)例。
?ServerSocket類方法:
方法簽 名 |
方法說明 |
---|---|
Socket accept() |
開始監(jiān)聽指定端口(創(chuàng)建時綁定的端口),有客戶端連接后,返回一個服務(wù)端Socket 對象,并基于該Socket建立與客戶端的連接,否則阻塞等待 |
void close() |
關(guān)閉此套接字 |
?第一個accept方法它是接收客戶端的信息,如果客戶端沒有請求,那它就會阻塞等待,如果有請求,就會建立連接,它的返回值是一個套接字。
3.3.2Socket類
?這個類就是創(chuàng)建一個套接字實(shí)例對象,他的成員變量有兩個:IP與端口號。
Socket類構(gòu)造方法:
方法簽名 | 方法說明 |
Socket(String host, int port) |
創(chuàng)建一個客戶端流套接字Socket,并與對應(yīng)IP的主機(jī)上,對應(yīng)端口的 進(jìn)程建立連接 |
Socket類方法:
方法簽名 | 方法說明 |
InetAddress getInetAddress() | 返回套接字所連接的地址 |
InputStream getInputStream() | 返回此套接字的輸入流 |
OutputStream getOutputStream() | 返回此套接字的輸出流 |
?3.3.3基于TCP的回顯程序
服務(wù)端?
?服務(wù)器設(shè)計邏輯:
- 創(chuàng)建一個ServerSocket類對象,指定服務(wù)器端口號。
- 開始運(yùn)行服務(wù)端;通過第一步實(shí)例好的對象調(diào)用accept方法,如果有無請求,就阻塞,如果有請求,就發(fā)到下面進(jìn)行處理。
- 進(jìn)入處理請求方法,將請求通過讀接收緩沖區(qū)寫入,再將寫入的請求發(fā)給處理程序進(jìn)行處理。
- 處理完畢后,將響應(yīng)發(fā)給客服端。
package TcpNetWork;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TcpEchoServer {
private ServerSocket serverSocket=null;
public TcpEchoServer(int port) throws IOException {
serverSocket=new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服務(wù)器啟動");
while (true) {
//接收到客服端請求
Socket clientSocket=serverSocket.accept();
//將請求發(fā)給解決請求的方法
processConnection(clientSocket);
}
}
private void processConnection(Socket clientSocket) throws IOException {
System.out.printf("[%s:%d] 客戶端上線了\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
try (InputStream inputStream=clientSocket.getInputStream();
OutputStream outputStream=clientSocket.getOutputStream()){
// 沒有這個 scanner 和 printWriter, 完全可以!! 但是代價就是得一個字節(jié)一個字節(jié)扣, 找到哪個是請求的結(jié)束標(biāo)記 \n
// 不是不能做, 而是代碼比較麻煩.
// 為了簡單, 把字節(jié)流包裝好了更方便的字符流~~
Scanner sc=new Scanner(inputStream);
PrintWriter printWriter=new PrintWriter(outputStream);
while (true) {
//1.接到客服端請求
if (!sc.hasNext()) {
System.out.printf("[%s:%d] 客戶端下線了\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
break;
}
String request=sc.next();
//2.對請求做出響應(yīng)
String response=process(request);
//3.把響應(yīng)返回給客戶端
printWriter.println(response);
printWriter.flush();
System.out.printf("[%s:%d] request:%s response:%s ",clientSocket.getInetAddress().toString(),
clientSocket.getPort(),request,response);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
clientSocket.close();
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoServer tcpEchoServer=new TcpEchoServer(9999);
tcpEchoServer.start();
}
}
客戶端
客戶端設(shè)計邏輯:
- 創(chuàng)建一個Socket實(shí)例,指定服務(wù)器的ip和端口號。
- 開啟客戶端,輸入請求,并刷新接收緩存區(qū)。
- 等到服務(wù)端給出響應(yīng),接收響應(yīng),對響應(yīng)做出動作。
package TcpNetWork;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class TcpEchoClient {
private Socket socket=null;
public TcpEchoClient(int port, String serverIp) throws IOException {
socket=new Socket(serverIp,port);
}
public void start() {
Scanner sc=new Scanner(System.in);
try(InputStream inputStream=socket.getInputStream();
OutputStream outputStream=socket.getOutputStream()) {
Scanner scannerFromSocket=new Scanner(inputStream);
PrintWriter printWriter=new PrintWriter(outputStream);
while (true) {
//1.從鍵盤上讀取請求
System.out.print("輸入指令->");
String request=sc.next();
//2.將請求發(fā)送給服務(wù)器端,并刷新接收緩存區(qū)
printWriter.println(request);
printWriter.flush();
//3.接收服務(wù)器端的信息
String response=scannerFromSocket.next();
//4.把信息打印到控制臺
System.out.printf("request:%s response:%s\n",request,response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
TcpEchoClient tcpEchoClient=new TcpEchoClient(9999,"127.0.0.1");
tcpEchoClient.start();
}
}
3.3.4對TCP回顯程序的優(yōu)化
在上方的程序中,我們只能對一個客戶端進(jìn)行提供服務(wù),這是因?yàn)槲覀冊诮邮盏牟糠纸o寫成了死循環(huán),如果出現(xiàn)第二個客戶端時,第二個客戶端只能進(jìn)行等待。我們?nèi)绾涡薷倪@個程序呢?這是我們就不得不提到多線程了,如果寫成多線程的話,就可以處理多個程序了。
程序代碼如下(服務(wù)端):?
package TcpNetWork;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TcpEchoServer {
private ServerSocket serverSocket=null;
public TcpEchoServer(int port) throws IOException {
serverSocket=new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服務(wù)器啟動");
while (true) {
//接收到客服端請求
Socket clientSocket=serverSocket.accept();
//將請求發(fā)給解決請求的方法
Thread t=new Thread(()->{
try {
processConnection(clientSocket);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
private void processConnection(Socket clientSocket) throws IOException {
System.out.printf("[%s:%d] 客戶端上線了\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
try (InputStream inputStream=clientSocket.getInputStream();
OutputStream outputStream=clientSocket.getOutputStream()){
// 沒有這個 scanner 和 printWriter, 完全可以!! 但是代價就是得一個字節(jié)一個字節(jié)扣, 找到哪個是請求的結(jié)束標(biāo)記 \n
// 不是不能做, 而是代碼比較麻煩.
// 為了簡單, 把字節(jié)流包裝好了更方便的字符流~~
Scanner sc=new Scanner(inputStream);
PrintWriter printWriter=new PrintWriter(outputStream);
while (true) {
//1.接到客服端請求
if (!sc.hasNext()) {
System.out.printf("[%s:%d] 客戶端下線了\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
break;
}
String request=sc.next();
//2.對請求做出響應(yīng)
String response=process(request);
//3.把響應(yīng)返回給客戶端
printWriter.println(response);
printWriter.flush();
System.out.printf("[%s:%d] request:%s response:%s ",clientSocket.getInetAddress().toString(),
clientSocket.getPort(),request,response);
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
clientSocket.close();
}
}
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoServer tcpEchoServer=new TcpEchoServer(9999);
tcpEchoServer.start();
}
}
如果我們想要去驗(yàn)證這個程序是否可以對多個客戶端提供服務(wù),我們還需要對其修改一點(diǎn)配置,不然我們不能將同一個類運(yùn)行兩次。
?1.右鍵鼠標(biāo),選擇修改運(yùn)行配置?
?2.點(diǎn)開之后,點(diǎn)擊修改選項(xiàng)?
?3.將允許多個實(shí)例打勾,這一我們就可以同時運(yùn)行多個實(shí)例了。
寫在最后:
??????以上就是本文全部內(nèi)容,如果對你有所幫助,希望能留下你的點(diǎn)贊+關(guān)注,我會更加努力的更新內(nèi)容!非常感謝??????
若本篇文章有錯誤的地方,歡迎大佬們指正!文章來源:http://www.zghlxwxcb.cn/news/detail-412227.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-412227.html
到了這里,關(guān)于【JaveEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!