国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【JavaEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字

這篇具有很好參考價(jià)值的文章主要介紹了【JavaEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

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中的長(zhǎng)短連接

3.3TCP套接字的API

3.3.2Socket類

3.3.3基于TCP的回顯程序

3.3.4對(duì)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ù)傳輸)。對(duì)于我們程序員來說,我們比較關(guān)注應(yīng)用層到傳輸層這一操作,我們代碼的書寫是發(fā)生在應(yīng)用層的,然后通過傳輸層提供的API(UDP和TCP)進(jìn)行包裝,再由應(yīng)用層發(fā)送給傳輸層。

1.1為什么需要網(wǎng)絡(luò)編程?

?這個(gè)最為直接的說話莫過于人民需要他了,哪里有需求,哪里就提供響應(yīng)嘛。

相比于本地的資源,網(wǎng)絡(luò)上有這更為豐富的資源,而網(wǎng)絡(luò)上的資源又需要通過網(wǎng)絡(luò)編程來上傳,因此就相互督促相互促進(jìn)了對(duì)方的發(fā)展。

1.2服務(wù)端與用戶端

服務(wù)端:在常見的網(wǎng)絡(luò)數(shù)據(jù)傳輸場(chǎng)景下,把提供服務(wù)的一方進(jìn)程,稱為服務(wù)端,可以提供對(duì)外服務(wù)。
客戶端:獲取服務(wù)的一方進(jìn)程,稱為客戶端。

簡(jiǎn)單的說,客戶端會(huì)接收到客戶的請(qǐng)求,再將客戶的請(qǐng)求發(fā)送給服務(wù)端;服務(wù)端將請(qǐng)求按照業(yè)務(wù)邏輯完成響應(yīng),再將響應(yīng)返回給客戶端,客戶端再將響應(yīng)按照操作顯示或者運(yùn)作。

【JavaEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字

1.3網(wǎng)絡(luò)編程五元組?

  1. 源IP:就是發(fā)送方IP.
  2. 源端口:發(fā)送方端口號(hào), 服務(wù)器需要手動(dòng)指定, 客戶端讓系統(tǒng)隨機(jī)分配即可.
  3. 目的IP: 接收方IP, 包含在拿到的數(shù)據(jù)報(bào)中, 服務(wù)器響應(yīng)時(shí)的目的IP就在客戶端發(fā)來的數(shù)據(jù)報(bào)中, 客戶端發(fā)送請(qǐng)求時(shí)的目的IP就是服務(wù)器的IP.
  4. 目的端口: 接收方端口號(hào)包含在數(shù)據(jù)報(bào)中, 服務(wù)器響應(yīng)時(shí)的目的端口就在客戶端發(fā)來的數(shù)據(jù)報(bào)中, 客戶端發(fā)送請(qǐng)求時(shí)的目的端口就是服務(wù)器的端口號(hào).
  5. 協(xié)議類型:如UDP/TCP.

1.4套接字的概念

Socket(套接字)可以看成是兩個(gè)網(wǎng)絡(luò)應(yīng)用程序進(jìn)行通信時(shí),各自通信連接中的端點(diǎn),這是一個(gè)邏輯上的概念。Socket是由IP地址和端口結(jié)合的,提供向應(yīng)用層進(jìn)程傳送數(shù)據(jù)包的機(jī)制?

套接字的表示方法:Socket=Ip接口:端口號(hào)

2.UDP套接字編程

2.1UDP套接字的特點(diǎn)

特點(diǎn)如下:

  • 無連接:不關(guān)心和誰對(duì)話,也不會(huì)刻意留意對(duì)方。
  • 不可靠的:不關(guān)心他收沒收到。
  • 面向數(shù)據(jù)報(bào):以一個(gè)UDP數(shù)據(jù)報(bào)為單位。
  • 全雙工通信:一條路徑,但是路徑兩方都可以對(duì)話。(雙向?qū)υ挘?/li>

【JavaEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字

?2.2UDP套接字API

UDP套接字的API中主要包括兩個(gè)類?:1.DatagramSocket 2.DatagramPacket。

下面就開始介紹這兩個(gè)類

2.2.1DatagramSocket類

?DatagramSocket類就是實(shí)例一個(gè)UDP版本的套接字也是就數(shù)據(jù)包套接字。Socket對(duì)象對(duì)應(yīng)到系統(tǒng)中的一個(gè)特殊文件(socket文件),socket文件不是數(shù)據(jù)存儲(chǔ)區(qū)域的一部分,而是對(duì)應(yīng)到網(wǎng)卡這個(gè)硬件設(shè)備,為什么對(duì)應(yīng)到網(wǎng)卡呢?因?yàn)榫W(wǎng)卡是一個(gè)硬件,對(duì)于代碼而已,不好直接操作,因此將它抽象成了一個(gè)文件進(jìn)行間接操作。

DatagramSocket類構(gòu)造方法:

方法簽名 方法說明
DatagramSocket() 創(chuàng)建一個(gè)UDP數(shù)據(jù)報(bào)套接字的Socket,綁定到本機(jī)任意一個(gè)隨機(jī)端口
(一般用于客戶端)
DatagramSocket(int
port)
創(chuàng)建一個(gè)UDP數(shù)據(jù)報(bào)套接字的Socket,綁定到本機(jī)指定的端口(一般用
于服務(wù)端)

我們一般使用第二個(gè)方法,我們知道端口號(hào)是在一個(gè)計(jì)算機(jī)中尋找一個(gè)程序的“門牌號(hào)”。實(shí)際操作時(shí),如果端口號(hào)是系統(tǒng)隨機(jī)綁定的話,我們就不知道我們服務(wù)端服務(wù)于哪一個(gè)客戶端了,就沒有辦法找到客戶端的家了。

DatagramSocket類方法:

方法簽名 方法說明
void
receive(DatagramPacket p)
從此套接字接收數(shù)據(jù)報(bào)(如果沒有接收到數(shù)據(jù)報(bào),該方法會(huì)阻
塞等待)
void send(DatagramPacket
p)
從此套接字發(fā)送數(shù)據(jù)報(bào)包(不會(huì)阻塞等待,直接發(fā)送)
void close() 關(guān)閉此數(shù)據(jù)報(bào)套接字

第一個(gè)receive方法它的參數(shù)需要準(zhǔn)備一個(gè)空的DatagramPacket對(duì)象(對(duì)象需要給予存儲(chǔ)空間),它把DatagramPacket實(shí)例對(duì)象再裝入到準(zhǔn)備好的空的DatagramPacket對(duì)象中去 ,為什么這樣做呢?就像我們平常接收東西時(shí),我們需要一個(gè)載體來承接這個(gè)物件,舉個(gè)例子吧,當(dāng)我們盛飯時(shí),我們不能夠直接用手去捧著飯,而是需要一個(gè)空飯盒去接打的飯。

第二個(gè)send方法他是DatagramPacket實(shí)例對(duì)象載入到接收緩沖區(qū)。

第三個(gè)close方法,因?yàn)镈atagramSocket類屬于文件資源,當(dāng)我們不用的時(shí)候,我們需要將它給手動(dòng)關(guān)閉了。

2.2.2DatagramPacket類?

DatagramPacket是UDP Socket發(fā)送和接收的數(shù)據(jù)報(bào)。?

DatagramPacket類構(gòu)造方法

方法簽名 方法說明
DatagramPacket(byte[]
buf, int length)
構(gòu)造一個(gè)DatagramPacket以用來接收數(shù)據(jù)報(bào),接收的數(shù)據(jù)保存在
字節(jié)數(shù)組(第一個(gè)參數(shù)buf)中,接收指定長(zhǎng)度(第二個(gè)參數(shù)
length)
DatagramPacket(byte[]
buf, int offset, int length,
SocketAddress address)
構(gòu)造一個(gè)DatagramPacket以用來發(fā)送數(shù)據(jù)報(bào),發(fā)送的數(shù)據(jù)為字節(jié)
數(shù)組(第一個(gè)參數(shù)buf)中,從0到指定長(zhǎng)度(第二個(gè)參數(shù)
length)。address指定目的主機(jī)的IP和端口號(hào)

這兩個(gè)構(gòu)造方法都會(huì)使用到,第一個(gè)構(gòu)造方法:他就是我們上方說的空的DatagramPacket對(duì)象也就是我們舉例說的“空飯盒”,第二個(gè)構(gòu)造方法是在我們將接收到的請(qǐng)求進(jìn)行封裝時(shí)使用的,假設(shè)我們接收到的請(qǐng)求是字符串,我們就要將它轉(zhuǎn)化成byte數(shù)組,再算出長(zhǎng)度,并且需要指定它要發(fā)送到那里去也就是SockerAddress類的一個(gè)子類InetSocketAddress類它里面包含目的ip和目的端口號(hào)。

DatagramPacket類方法:

方法簽名 方法說明
InetAddress
getAddress()
從接收的數(shù)據(jù)報(bào)中,獲取發(fā)送端主機(jī)IP地址;或從發(fā)送的數(shù)據(jù)報(bào)中,獲取
接收端主機(jī)IP地址
int getPort() 從接收的數(shù)據(jù)報(bào)中,獲取發(fā)送端主機(jī)的端口號(hào);或從發(fā)送的數(shù)據(jù)報(bào)中,獲
取接收端主機(jī)端口號(hào)
byte[] getData() 獲取數(shù)據(jù)報(bào)中的數(shù)據(jù)

2.2.3基于UDP的回顯程序

UDP服務(wù)端:

服務(wù)器設(shè)計(jì)邏輯:?

  1. ?創(chuàng)建DatagramSocket對(duì)象,指定服務(wù)器端口號(hào)。
  2. 服務(wù)器啟動(dòng)了,我們需要一個(gè)DatagramPacket實(shí)例運(yùn)來當(dāng)作載體,當(dāng)沒有請(qǐng)求時(shí),在這里就會(huì)發(fā)生阻塞,有請(qǐng)求時(shí),就寫入到DatagramPacket實(shí)例好的載體中。
  3. 接收到數(shù)據(jù)后,我們將數(shù)據(jù)拆分成我們需要的格式,因?yàn)槲覀兪且粋€(gè)回顯,故我們只需將它改成字符串就行了,再調(diào)用process方法,在這里完成業(yè)務(wù)需求,我們這里只需返回字符串就像了。
  4. 將處理好的請(qǐng)求,再封裝一下,封裝成DatagramPacket實(shí)例對(duì)象,將這個(gè)響應(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ù)器啟動(dòng)");
        while (true) {
            //requestPacket是一個(gè)載體,receive方法會(huì)將發(fā)送過來的數(shù)據(jù)放入到這個(gè)載體中
            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è)計(jì)邏輯:

  1. ?客戶端需要知道服務(wù)端的位置,因此我們需要服務(wù)端的ip地址和端口號(hào),故成員變量包含Ipserver、serverPort以及一個(gè)DatagramSocket對(duì)象(可以理解為整合ip和端口號(hào))。
  2. 開始運(yùn)行客戶端,通過Scaner接收客戶的請(qǐng)求。
  3. 拿到請(qǐng)求后,我們需要將它封裝成DatagramPacket對(duì)象,發(fā)送給服務(wù)端。
  4. 發(fā)送完就等待服務(wù)端返回響應(yīng)。
  5. 等到拿到響應(yīng)之后,我們就可以對(duì)響應(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的單詞查詢?

對(duì)于這個(gè)服務(wù)端,我們不需要再寫一邊start方法了,我們可以直接讓它繼承udpEchoServer類,并且,我們?cè)谏戏椒?wù)端,我們將對(duì)請(qǐng)求處理的部分拿出來當(dāng)作了一個(gè)單獨(dú)的函數(shù),我們?cè)趯⑸戏降暮瘮?shù)進(jìn)行重寫就行了,還有就是,我們需要一個(gè)存儲(chǔ)單詞,并且它還方便查詢的東西,我們就想到一個(gè)數(shù)據(jù)結(jié)構(gòu)就是Map,剛好可以適合這個(gè)系統(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ù). 有道詞典和咱們相比, 就是人家的這個(gè)表更大!!
    }

    @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)如下:

  1. 有鏈接:雙方通信,都需要可以留意對(duì)方信息。
  2. 可靠傳輸:盡可能的將數(shù)據(jù)傳輸給對(duì)方,但也不能保證100%。
  3. 面向字節(jié)流:以一個(gè)字節(jié)傳輸為基本單位。
  4. 全雙工:雙方都可以向?qū)Ψ桨l(fā)送信息。

3.2TCP中的長(zhǎng)短連接

TCP發(fā)送數(shù)據(jù)時(shí),需要先建立連接,什么時(shí)候關(guān)閉連接就決定是短連接還是長(zhǎng)連接
短連接:每次接收到數(shù)據(jù)并返回響應(yīng)后,都關(guān)閉連接,即是短連接。也就是說,短連接只能一次收發(fā)數(shù)據(jù)。
長(zhǎng)連接:不關(guān)閉連接,一直保持連接狀態(tài),雙方不停的收發(fā)數(shù)據(jù),即是長(zhǎng)連接。也就是說,長(zhǎng)連接可以多次收發(fā)數(shù)據(jù)。

長(zhǎng)連接與短鏈接的區(qū)別:

  • 建立連接、關(guān)閉連接的耗時(shí):短連接每次請(qǐng)求、響應(yīng)都需要建立連接,關(guān)閉連接;而長(zhǎng)連接只需要第一次建立連接,之后的請(qǐng)求、響應(yīng)都可以直接傳輸。相對(duì)來說建立連接,關(guān)閉連接也是要耗時(shí)的,長(zhǎng)連接效率更高。
  • 主動(dòng)發(fā)送請(qǐng)求不同:短連接一般是客戶端主動(dòng)向服務(wù)端發(fā)送請(qǐng)求;而長(zhǎng)連接可以是客戶端主動(dòng)發(fā)送請(qǐng)求,也可以是服務(wù)端主動(dòng)發(fā)。
  • 兩者的使用場(chǎng)景有不同:短連接適用于客戶端請(qǐng)求頻率不高的場(chǎng)景,如瀏覽網(wǎng)頁等。長(zhǎng)連接適用于客戶端與服務(wù)端通信頻繁的場(chǎng)景,如聊天室,實(shí)時(shí)游戲等。

3.3TCP套接字的API

TCP套接字的API中主要包含兩個(gè)類:1.ServerSocket 2.Socket

下面介紹這兩個(gè)類

3.3.1ServerSocket類

這個(gè)類是在看名字就很好理解,它主要用于服務(wù)端,它的作用是創(chuàng)建一個(gè)服務(wù)端套接字。

?ServerSocket類構(gòu)造方法:

方法簽名 方法說明
ServerSocket(int port) 創(chuàng)建一個(gè)服務(wù)端流套接字Socket,并綁定到指定端口

在實(shí)例對(duì)象時(shí),我們就將端口號(hào)傳進(jìn)來,完成實(shí)例。

?ServerSocket類方法:

方法簽
方法說明
Socket
accept()
開始監(jiān)聽指定端口(創(chuàng)建時(shí)綁定的端口),有客戶端連接后,返回一個(gè)服務(wù)端Socket
對(duì)象,并基于該Socket建立與客戶端的連接,否則阻塞等待
void
close()
關(guān)閉此套接字

?第一個(gè)accept方法它是接收客戶端的信息,如果客戶端沒有請(qǐng)求,那它就會(huì)阻塞等待,如果有請(qǐng)求,就會(huì)建立連接,它的返回值是一個(gè)套接字。

3.3.2Socket類

?這個(gè)類就是創(chuàng)建一個(gè)套接字實(shí)例對(duì)象,他的成員變量有兩個(gè):IP與端口號(hào)。

Socket類構(gòu)造方法:

方法簽名 方法說明
Socket(String host, int
port)
創(chuàng)建一個(gè)客戶端流套接字Socket,并與對(duì)應(yīng)IP的主機(jī)上,對(duì)應(yīng)端口的
進(jìn)程建立連接

Socket類方法:

方法簽名 方法說明
InetAddress getInetAddress() 返回套接字所連接的地址
InputStream getInputStream() 返回此套接字的輸入流
OutputStream getOutputStream() 返回此套接字的輸出流

?3.3.3基于TCP的回顯程序

服務(wù)端?

?服務(wù)器設(shè)計(jì)邏輯:

  1. 創(chuàng)建一個(gè)ServerSocket類對(duì)象,指定服務(wù)器端口號(hào)。
  2. 開始運(yùn)行服務(wù)端;通過第一步實(shí)例好的對(duì)象調(diào)用accept方法,如果有無請(qǐng)求,就阻塞,如果有請(qǐng)求,就發(fā)到下面進(jìn)行處理。
  3. 進(jìn)入處理請(qǐng)求方法,將請(qǐng)求通過讀接收緩沖區(qū)寫入,再將寫入的請(qǐng)求發(fā)給處理程序進(jìn)行處理。
  4. 處理完畢后,將響應(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ù)器啟動(dòng)");
        while (true) {
            //接收到客服端請(qǐng)求
            Socket clientSocket=serverSocket.accept();
            //將請(qǐng)求發(fā)給解決請(qǐng)求的方法
            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()){
            // 沒有這個(gè) scanner 和 printWriter, 完全可以!! 但是代價(jià)就是得一個(gè)字節(jié)一個(gè)字節(jié)扣, 找到哪個(gè)是請(qǐng)求的結(jié)束標(biāo)記 \n
            // 不是不能做, 而是代碼比較麻煩.
            // 為了簡(jiǎn)單, 把字節(jié)流包裝好了更方便的字符流~~
            Scanner sc=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            while (true) {
                //1.接到客服端請(qǐng)求
                if (!sc.hasNext()) {
                    System.out.printf("[%s:%d] 客戶端下線了\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
                    break;
                }
                String request=sc.next();
                //2.對(duì)請(qǐng)求做出響應(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è)計(jì)邏輯:

  1. 創(chuàng)建一個(gè)Socket實(shí)例,指定服務(wù)器的ip和端口號(hào)。
  2. 開啟客戶端,輸入請(qǐng)求,并刷新接收緩存區(qū)。
  3. 等到服務(wù)端給出響應(yīng),接收響應(yīng),對(duì)響應(yīng)做出動(dò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.從鍵盤上讀取請(qǐng)求
                System.out.print("輸入指令->");
                String request=sc.next();
                //2.將請(qǐng)求發(fā)送給服務(wù)器端,并刷新接收緩存區(qū)
                printWriter.println(request);
                printWriter.flush();
                //3.接收服務(wù)器端的信息
                String response=scannerFromSocket.next();
                //4.把信息打印到控制臺(tái)
                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對(duì)TCP回顯程序的優(yōu)化

在上方的程序中,我們只能對(duì)一個(gè)客戶端進(jìn)行提供服務(wù),這是因?yàn)槲覀冊(cè)诮邮盏牟糠纸o寫成了死循環(huán),如果出現(xiàn)第二個(gè)客戶端時(shí),第二個(gè)客戶端只能進(jìn)行等待。我們?nèi)绾涡薷倪@個(gè)程序呢?這是我們就不得不提到多線程了,如果寫成多線程的話,就可以處理多個(gè)程序了。

程序代碼如下(服務(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ù)器啟動(dòng)");
        while (true) {
            //接收到客服端請(qǐng)求
            Socket clientSocket=serverSocket.accept();
            //將請(qǐng)求發(fā)給解決請(qǐng)求的方法
            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()){
            // 沒有這個(gè) scanner 和 printWriter, 完全可以!! 但是代價(jià)就是得一個(gè)字節(jié)一個(gè)字節(jié)扣, 找到哪個(gè)是請(qǐng)求的結(jié)束標(biāo)記 \n
            // 不是不能做, 而是代碼比較麻煩.
            // 為了簡(jiǎn)單, 把字節(jié)流包裝好了更方便的字符流~~
            Scanner sc=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            while (true) {
                //1.接到客服端請(qǐng)求
                if (!sc.hasNext()) {
                    System.out.printf("[%s:%d] 客戶端下線了\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
                    break;
                }
                String request=sc.next();
                //2.對(duì)請(qǐng)求做出響應(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)證這個(gè)程序是否可以對(duì)多個(gè)客戶端提供服務(wù),我們還需要對(duì)其修改一點(diǎn)配置,不然我們不能將同一個(gè)類運(yùn)行兩次。

?1.右鍵鼠標(biāo),選擇修改運(yùn)行配置?

【JavaEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字?2.點(diǎn)開之后,點(diǎn)擊修改選項(xiàng)?

【JavaEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字?3.將允許多個(gè)實(shí)例打勾,這一我們就可以同時(shí)運(yùn)行多個(gè)實(shí)例了。

【JavaEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字


寫在最后:

??????以上就是本文全部?jī)?nèi)容,如果對(duì)你有所幫助,希望能留下你的點(diǎn)贊+關(guān)注,我會(huì)更加努力的更新內(nèi)容!非常感謝??????

若本篇文章有錯(cuò)誤的地方,歡迎大佬們指正!

【JavaEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字文章來源地址http://www.zghlxwxcb.cn/news/detail-419416.html

到了這里,關(guān)于【JavaEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 網(wǎng)絡(luò)編程【TCP流套接字編程】

    網(wǎng)絡(luò)編程【TCP流套接字編程】

    目錄 TCP流套接字編程 1.ServerSocket API 2.Socket API 3.TCP中的長(zhǎng)短連接 4.回顯程序(短連接) 5.服務(wù)器和客戶端它們的交互過程 6.運(yùn)行結(jié)果及修改代碼 ? ??兩個(gè)核心: ServerSocket? ? ?Socket 1.ServerSocket API ? ServerSocket 是創(chuàng)建?TCP服務(wù)端Socket的API ServerSocket 構(gòu)造方法: ServerSocket 方法 :

    2023年04月12日
    瀏覽(573)
  • 網(wǎng)絡(luò)編程套接字( TCP )

    網(wǎng)絡(luò)編程套接字( TCP )

    目錄 1、實(shí)現(xiàn)一個(gè)TCP網(wǎng)絡(luò)程序(單進(jìn)程版) ????????1.1、服務(wù)端serverTcp.cc文件 ?????????????????服務(wù)端創(chuàng)建套接字 ?????????????????服務(wù)端綁定 ?????????????????服務(wù)端監(jiān)聽 ?????????????????服務(wù)端獲取連接 ?????????????????服務(wù)

    2024年01月17日
    瀏覽(1815)
  • 【JaveEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字

    【JaveEE】網(wǎng)絡(luò)編程之TCP套接字、UDP套接字

    目錄 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套接字的特

    2023年04月13日
    瀏覽(915)
  • 【網(wǎng)絡(luò)編程】網(wǎng)絡(luò)編程套接字(三)TCP網(wǎng)絡(luò)程序

    【網(wǎng)絡(luò)編程】網(wǎng)絡(luò)編程套接字(三)TCP網(wǎng)絡(luò)程序

    與前邊的UDP網(wǎng)絡(luò)程序相同,創(chuàng)建套接字的接口都是socket,下邊對(duì)socket接口進(jìn)行介紹: 協(xié)議家族選擇AF_INET,因?yàn)槲覀円M(jìn)行網(wǎng)絡(luò)通信。 而第二個(gè)參數(shù),為服務(wù)類型,傳入SOCK_STREAM,我們編寫TCP程序,所以要選擇流式的服務(wù)。 第三個(gè)參數(shù)默認(rèn)傳入0,由前兩個(gè)參數(shù)就可以推出這是

    2024年02月16日
    瀏覽(91)
  • 【Linux網(wǎng)絡(luò)】網(wǎng)絡(luò)編程套接字(TCP)

    【Linux網(wǎng)絡(luò)】網(wǎng)絡(luò)編程套接字(TCP)

    目錄 地址轉(zhuǎn)換函數(shù) 字符串IP轉(zhuǎn)整數(shù)IP 整數(shù)IP轉(zhuǎn)字符串IP 關(guān)于inet_ntoa 簡(jiǎn)單的單執(zhí)行流TCP網(wǎng)絡(luò)程序 TCP socket API 詳解及封裝TCP socket? 服務(wù)端創(chuàng)建套接字? 服務(wù)端綁定? 服務(wù)端監(jiān)聽? 服務(wù)端獲取連接? 服務(wù)端處理請(qǐng)求 客戶端創(chuàng)建套接字 客戶端連接服務(wù)器 客戶端發(fā)起請(qǐng)求 服務(wù)器測(cè)試

    2024年03月21日
    瀏覽(112)
  • 【Linux】網(wǎng)絡(luò)---->套接字編程(TCP)

    【Linux】網(wǎng)絡(luò)---->套接字編程(TCP)

    TCP的編程流程:大致可以分為五個(gè)過程,分別是準(zhǔn)備過程、連接建立過程、獲取新連接過程、消息收發(fā)過程和斷開過程。 1.準(zhǔn)備過程:服務(wù)端和客戶端需要?jiǎng)?chuàng)建各自的套接字,除此之外服務(wù)端還需要綁定自己的地址信息和進(jìn)行監(jiān)聽。注意:服務(wù)端調(diào)用listen函數(shù)后,處理監(jiān)聽狀

    2024年02月04日
    瀏覽(101)
  • Linux網(wǎng)絡(luò)編程——tcp套接字

    Linux網(wǎng)絡(luò)編程——tcp套接字

    本章Gitee倉庫:tcp套接字 客戶端: 客戶端: 關(guān)于構(gòu)造和初始化,可以直接在構(gòu)造的時(shí)候,將服務(wù)器初始化,那為什么還要寫到 init 初始化函數(shù)里面呢? 構(gòu)造盡量簡(jiǎn)單一點(diǎn),不要做一些“有風(fēng)險(xiǎn)”的操作。 tcp 是面向連接的,通信之前要建立連接,服務(wù)器處于等待連接到來的

    2024年02月20日
    瀏覽(95)
  • 網(wǎng)絡(luò)編程套接字之三【TCP】

    網(wǎng)絡(luò)編程套接字之三【TCP】

    目錄 1. ServerSocket API(給服務(wù)器端使用的類) 2. Socket API(既給服務(wù)器使用,也給客戶端使用) 3. 寫TCP回顯—服務(wù)器 4. 使用線程池后的TCP服務(wù)器代碼(最終) 5. 寫回顯-客戶端 6. TCP回顯—客戶端代碼 7. 運(yùn)行回顯服務(wù)器和客戶端 TCP流套接字編程 ?ServerSocket 是創(chuàng)建TCP服務(wù)端Socket的

    2024年01月19日
    瀏覽(91)
  • 網(wǎng)絡(luò)編程套接字(2)——簡(jiǎn)單的TCP網(wǎng)絡(luò)程序

    網(wǎng)絡(luò)編程套接字(2)——簡(jiǎn)單的TCP網(wǎng)絡(luò)程序

    我們將TCP服務(wù)器封裝成一個(gè)類,當(dāng)我們定義出一個(gè)服務(wù)器對(duì)象后需要馬上對(duì)服務(wù)器進(jìn)行初始化,而初始化TCP服務(wù)器要做的第一件事就是創(chuàng)建套接字。 TCP服務(wù)器在調(diào)用socket函數(shù)創(chuàng)建套接字時(shí),參數(shù)設(shè)置如下: 協(xié)議家族選擇 AF_INET ,因?yàn)槲覀円M(jìn)行的是網(wǎng)絡(luò)通信。 創(chuàng)建套接字時(shí)

    2024年02月06日
    瀏覽(92)
  • 【Linux網(wǎng)絡(luò)編程】網(wǎng)絡(luò)編程套接字(TCP服務(wù)器)

    【Linux網(wǎng)絡(luò)編程】網(wǎng)絡(luò)編程套接字(TCP服務(wù)器)

    作者:愛寫代碼的剛子 時(shí)間:2024.4.4 前言:本篇博客主要介紹TCP及其服務(wù)器編碼 只介紹基于IPv4的socket網(wǎng)絡(luò)編程,sockaddr_in中的成員struct in_addr sin_addr表示32位 的IP地址 但是我們通常用點(diǎn)分十進(jìn)制的字符串表示IP地址,以下函數(shù)可以在字符串表示和in_addr表示之間轉(zhuǎn)換 字符串轉(zhuǎn)in

    2024年04月14日
    瀏覽(107)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包