java中TCP/UDP詳細(xì)總結(jié)
TCP/UDP:TCP主要是面向連接的協(xié)議,它包含有建立和拆除連接,保證數(shù)據(jù)流的順序和正確性等功能。
每次對(duì)TCP中間的數(shù)據(jù)操作相當(dāng)于對(duì)一個(gè)數(shù)據(jù)流進(jìn)行訪(fǎng)問(wèn)。它最典型的特征就是那三次握手的建立連接過(guò)程。Server端所要做的事情主要是建立一個(gè)通信的端點(diǎn),然后等待客戶(hù)端發(fā)送的請(qǐng)求。典型的處理步驟如下:
1. 構(gòu)建一個(gè)ServerSocket實(shí)例,指定本地的端口。這個(gè)socket就是用來(lái)監(jiān)聽(tīng)指定端口的連接請(qǐng)求的。
2.重復(fù)如下幾個(gè)步驟:
a. 調(diào)用socket的accept()方法來(lái)獲得下面客戶(hù)端的連接請(qǐng)求。通過(guò)accept()方法返回的socket實(shí)例,建立了一個(gè)和客戶(hù)端的新連接。
b.通過(guò)這個(gè)返回的socket實(shí)例獲取InputStream和OutputStream,可以通過(guò)這兩個(gè)stream來(lái)分別讀和寫(xiě)數(shù)據(jù)。
c.結(jié)束的時(shí)候調(diào)用socket實(shí)例的close()方法關(guān)閉socket連接。
TCP服務(wù)器端:
public class TCPServer {
public static void main(String[] args){
try{
ServerSocket server=new ServerSocket();
SocketAddress address=new InetSocketAddress(InetAddress.getLocalHost(),10001);
server.bind(address);
System.out.println("等待連接客戶(hù)端...");
Socket client = server.accept();
System.out.println("connected with"+client.getRemoteSocketAddress());
PrintWriter socketOut = new PrintWriter(client.getOutputStream());
System.out.println("等待客戶(hù)端的消息...");
byte buf[] = new byte[1024];
if ( client.getInputStream().read(buf) > 0 ) {
System.out.println("收到的消息: " + new String(buf));
}
System.out.println("發(fā)送消息給客戶(hù)端...");
String sendStr = "服務(wù)器返回的信息";
socketOut.write(sendStr);
socketOut.flush();
socketOut.close();
client.close();
server.close();
}catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
TCP客戶(hù)端:
1.構(gòu)建Socket實(shí)例,通過(guò)指定的遠(yuǎn)程服務(wù)器地址和端口來(lái)建立連接。
2.通過(guò)Socket實(shí)例包含的InputStream和OutputStream來(lái)進(jìn)行數(shù)據(jù)的讀寫(xiě)。
3.操作結(jié)束后調(diào)用socket實(shí)例的close方法,關(guān)閉。
public class TCPClient {
public static void main(String[] args){
try{
final Socket socket = new Socket();
SocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 10001);
System.out.println("連接服務(wù)端 ...");
socket.connect(address);
PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
BufferedReader socketIn = new BufferedReader(
new InputStreamReader(socket.getInputStream()) );
String sendStr = "客戶(hù)端發(fā)送的消息";
System.out.println("發(fā)送消息給服務(wù)端 ...");
socketOut.write(sendStr);
socketOut.flush();
System.out.println("等待服務(wù)端的消息 ...");
String receiveStr = socketIn.readLine();
System.out.println("收到的消息: " + receiveStr);
socketOut.close();
socketIn.close();
socket.close();
}catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
UDP(User Datagram Protocol,用戶(hù)數(shù)據(jù)報(bào)協(xié)議)
UDP和TCP有兩個(gè)典型的區(qū)別,一個(gè)就是它不需要建立連接,另外就是它在每次收發(fā)的報(bào)文都保留了消息的邊界。
因?yàn)閁DP協(xié)議不需要建立連接,它的過(guò)程如下:
1. 構(gòu)造DatagramSocket實(shí)例,指定本地端口。
2. 通過(guò)DatagramSocket實(shí)例的receive方法接收DatagramPacket.DatagramPacket中間就包含了通信的內(nèi)容。
3. 通過(guò)DatagramSocket的send和receive方法來(lái)收和發(fā)DatagramPacket.
public class UDPServer {
public static void main(String args[]) {
DatagramSocket socket = null;
DatagramPacket datapacket = null;
InetSocketAddress address = null;
try {
address = new InetSocketAddress(InetAddress.getLocalHost(), 7778);
socket = new DatagramSocket(address);
// socket.bind(address);
byte buf[] = new byte[1024];
datapacket = new DatagramPacket(buf, buf.length);
System.out.println("block for receive messages...");
socket.receive(datapacket);
buf = datapacket.getData();
InetAddress addr = datapacket.getAddress();
int port = datapacket.getPort();
System.out.println("Message Content: " + new String(buf) );
System.out.println("Receive From " + addr + ":" + port);
SocketAddress toAddress = datapacket.getSocketAddress();
String sendStr = "I'm Server, this is the message for client.";
buf = sendStr.getBytes();
datapacket = new DatagramPacket(buf, buf.length);
datapacket.setSocketAddress(toAddress);
socket.send(datapacket);
System.out.println("message sended");
//釋放資源
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
UDP客戶(hù)端的步驟也比較簡(jiǎn)單,主要包括下面3步:
1. 構(gòu)造DatagramSocket實(shí)例。
2.通過(guò)DatagramSocket實(shí)例的send和receive方法發(fā)送DatagramPacket報(bào)文。
3.結(jié)束后,調(diào)用DatagramSocket的close方法關(guān)閉。
因?yàn)楹蚑CP不同,UDP發(fā)送報(bào)文的時(shí)候可以在同一個(gè)本地端口隨意發(fā)送給不同的服務(wù)器,一般不需要在UDP的DatagramSocket的構(gòu)造函數(shù)中指定目的服務(wù)器的地址。
另外,UDP客戶(hù)端還有一個(gè)重要的不同就是,TCP客戶(hù)端發(fā)送echo連接消息之后會(huì)在調(diào)用read方法的時(shí)候進(jìn)入阻塞狀態(tài),而UDP這樣卻不行。因?yàn)閁DP中間是可以允許報(bào)文丟失的。如果報(bào)文丟失了,進(jìn)程一直在阻塞或者掛起的狀態(tài),則進(jìn)程會(huì)永遠(yuǎn)沒(méi)法往下走了。
所以會(huì)一般設(shè)置一個(gè)setSoTimeout方法,指定在多久的時(shí)間內(nèi)沒(méi)有收到報(bào)文就放棄。也可以通過(guò)指定一個(gè)數(shù)字,循環(huán)指定的次數(shù)來(lái)讀取報(bào)文,讀到就返回,否則就放棄。
public class UDPClient {
public static void main(String args[]) {
try {
DatagramSocket getSocket = new DatagramSocket();
DatagramPacket datapacket = null;
InetSocketAddress toAddress = new InetSocketAddress(InetAddress.getLocalHost(), 7778);
String sendStr = "I'm client, this is the message for server.";
byte buf[] = sendStr.getBytes();
datapacket = new DatagramPacket(buf, buf.length);
datapacket.setSocketAddress(toAddress);
getSocket.send(datapacket);
System.out.println("message sended");
System.out.println("block for receive messages...");
getSocket.receive(datapacket);
buf = datapacket.getData();
System.out.println("Message Content: " + new String(buf));
getSocket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
以上內(nèi)容,需要的朋友可以參考
相關(guān)文章
IntelliJ IDEA安裝目錄和設(shè)置目錄的說(shuō)明(IntelliJ IDEA快速入門(mén))
這篇文章主要介紹了IntelliJ IDEA安裝目錄和設(shè)置目錄的說(shuō)明(IntelliJ IDEA快速入門(mén)),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
如何基于mybatis框架查詢(xún)數(shù)據(jù)庫(kù)表數(shù)據(jù)并打印
這篇文章主要介紹了如何基于mybatis框架查詢(xún)數(shù)據(jù)庫(kù)表數(shù)據(jù)并打印,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
SpringMVC中的請(qǐng)求參數(shù)接收方式
這篇文章主要介紹了SpringMVC中的請(qǐng)求參數(shù)接收方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-04-04
Java實(shí)現(xiàn)將每日新聞添加到自己博客中
這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)將每日新聞添加到自己博客中并發(fā)送到微信群中,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-12-12
關(guān)于springboot2.4跨域配置問(wèn)題
這篇文章主要介紹了springboot2.4跨域配置的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
SpringBoot實(shí)現(xiàn)微信小程序支付功能
小程序支付功能已成為眾多應(yīng)用的核心需求之一,本文主要介紹了SpringBoot實(shí)現(xiàn)微信小程序支付功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04
Springboot實(shí)現(xiàn)多線(xiàn)程及線(xiàn)程池監(jiān)控
線(xiàn)程池的監(jiān)控很重要,本文就來(lái)介紹一下Springboot實(shí)現(xiàn)多線(xiàn)程及線(xiàn)程池監(jiān)控,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-01-01

