日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java网络编程之Socket编程

發(fā)布時(shí)間:2025/3/8 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java网络编程之Socket编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

概念

網(wǎng)絡(luò)編程分為BIO(傳統(tǒng)IO)、NIO、AIO。Socket編程屬于BIO這種傳統(tǒng)IO。

InetAddress

  java.net.InetAddress是JAVA中管理IP地址的類,常用

  

  

  public static void main(String[] args) throws UnknownHostException {InetAdressDemo.getLocalHost();System.out.println("---------------------------");getHostByName("Lenovo-Autumn");}/*** 獲取主機(jī)ip和主機(jī)名* @throws UnknownHostException*/public static void getLocalHost() throws UnknownHostException {//根據(jù)InetAddress獲取主機(jī)名和主機(jī)ipInetAddress localHost = InetAddress.getLocalHost();System.out.println(localHost); //打印:Lenovo-Autumn/192.168.56.1//根據(jù)getLocalHost()返回的值獲取ip和主機(jī)名String hostName = localHost.getHostName();String hostAddress = localHost.getHostAddress();System.out.println(hostName); //打印 Lenovo-AutumnSystem.out.println(hostAddress); //打印 192.168.56.1//根據(jù)切割獲取主機(jī)名和ipString[] str = localHost.toString().split("/");System.out.println(str[0]); //打印 Lenovo-AutumnSystem.out.println(str[1]); //打印 192.168.56.1 }/*** 根據(jù)主機(jī)名稱獲取ip地址* @param otherName 主機(jī)名(可以是局域網(wǎng)中的機(jī)器名或者是域名或者是ip)* @throws UnknownHostException*/public static void getHostByName(String otherName) throws UnknownHostException {InetAddress otherHost = InetAddress.getByName(otherName);String hostName = otherHost.getHostName();String hostAddress = otherHost.getHostAddress();System.out.println(hostName); //打印 Lenovo-AutumnSystem.out.println(hostAddress); //打印 192.168.56.1System.out.println(otherHost); //打印:Lenovo-Autumn/192.168.56.1}

  code

UDP

  發(fā)送數(shù)據(jù)時(shí)必須指定接收端的IP地址和端口號(hào),就好像發(fā)送貨物的集裝箱上面必須標(biāo)明接收人的地址一樣。

  接收端不需要明確知道數(shù)據(jù)的來(lái)源,只需要接收到數(shù)據(jù)即可。

  java.net.DatagramPackage

構(gòu)造函數(shù):

第一種是用來(lái)接受的數(shù)據(jù)包,不需要指定IP和端口,第二種是用來(lái)發(fā)送的數(shù)據(jù)包需要指定ip和端口

方法:

獲取ip地址,獲取服務(wù)器ip或者客戶端ip

  

  返回端口號(hào),獲取發(fā)送方或者

  返回?cái)?shù)據(jù)緩沖區(qū)

  

  返回要發(fā)送或接受的數(shù)據(jù)包大小

  java.net.DatagramSocket

  DatagramPacket數(shù)據(jù)包的作用就如同是“集裝箱”,可以將發(fā)送端或者接收端的數(shù)據(jù)封裝起來(lái)。然而運(yùn)輸貨物只有“集裝箱”是不夠的,還需要有碼頭。在程序中需要實(shí)現(xiàn)通信只有DatagramPacket數(shù)據(jù)包也同樣不行,為此JDK中提供的一個(gè)DatagramSocket類。DatagramSocket類的作用就類似于碼頭,使用這個(gè)類的實(shí)例對(duì)象就可以發(fā)送和接收DatagramPacket數(shù)據(jù)包,發(fā)送數(shù)據(jù)的過(guò)程如下圖所示。

構(gòu)造函數(shù):

用來(lái)創(chuàng)建發(fā)送端的DatagramSocket對(duì)象

用來(lái)創(chuàng)建接收端的DatagramSocket對(duì)象

  方法:

發(fā)送數(shù)據(jù)報(bào)包

接收數(shù)據(jù)報(bào)包

發(fā)送端

1, ?創(chuàng)建DatagramSocket對(duì)象

DatagramSocket()

2,創(chuàng)建DatagramPacket對(duì)象,封裝數(shù)據(jù),并指定ip和端口。

    DatagramPacket(byte[] buf, int length, InetAddress address, int port)  

3,發(fā)送數(shù)據(jù)

    socket.send(DatagramPacket dp)

4,釋放流資源

ds.close();

接收端

1,創(chuàng)建DatagramSocket對(duì)象,只需要指定端口

    DatagramSocket(port)

2,創(chuàng)建DatagramPacket對(duì)象

    DatagramPacket(byte[] data, int?length)

3,接收數(shù)據(jù)存儲(chǔ)到DatagramPacket對(duì)象中 

    receive(DatagramPackage dp)

4,獲取DatagramPacket對(duì)象的內(nèi)容   

    new String(data,0,dp.getLength());

5,釋放流資源

    ds.close();

/*** 實(shí)現(xiàn)udp發(fā)送端* 用java.net.DatagramPackage封裝數(shù)據(jù)* 用java.net.DatagramSocket發(fā)送數(shù)據(jù)** 實(shí)現(xiàn)步驟* 1.用DatagramPackage對(duì)象,封裝數(shù)據(jù),接受的地址和端口* 2.創(chuàng)建DatagramSocket* 3.調(diào)用DatagramSocket對(duì)象send方法,發(fā)送數(shù)據(jù)* 4.關(guān)閉資源** DatagramPackage構(gòu)造函數(shù)* DatagramPacket(byte[] buf, int length, InetAddress address, int port)* DatagramSocket構(gòu)造函數(shù)* DatagramSocket()* 方法:send(DatagramPacket d)* Created by Autumn on 2018/2/5.*/ public class UdpSend {public static void main(String[] args) throws Exception {Scanner scanner = new Scanner(System.in);//獲取地址InetAddress inet = InetAddress.getByName("127.0.0.1");//創(chuàng)建DatagramSocket,負(fù)責(zé)接受和發(fā)送數(shù)據(jù)DatagramSocket ds = new DatagramSocket();while(true){String msg = scanner.nextLine();//創(chuàng)建數(shù)據(jù)包對(duì)象對(duì)象byte[] data = msg.getBytes();//封裝數(shù)據(jù),接受的地址和端口DatagramPacket dp = new DatagramPacket(data,data.length,inet,6000);//發(fā)送數(shù)據(jù)包 ds.send(dp);if(msg.equals("exit")){break;}}//關(guān)閉 ds.close();} }/*** 實(shí)現(xiàn)udp接收端* 用java.net.DatagramPackage 接受數(shù)據(jù)* 用java.net.DatagramSocket 接受數(shù)據(jù)包** 步驟* 1.創(chuàng)建DatagramSocket對(duì)象,綁定端口號(hào)(要和發(fā)送端端口一致)* 2.創(chuàng)建字節(jié)數(shù)組用來(lái)接受數(shù)據(jù)* 3.創(chuàng)建數(shù)據(jù)對(duì)象包DatagramPackage* 4.創(chuàng)建DatagramSocket* receive(DatagramPackage dp)接受數(shù)據(jù),將數(shù)據(jù)封裝如dp中* 5.拆包* 發(fā)送端的ip地址(DatagramPackage.get)* 接受到的字節(jié)數(shù)組* 發(fā)送的端口號(hào)* 6.關(guān)閉資源* Created by Autumn on 2018/2/5.*/ public class UdpReceive {public static void main(String[] args) throws IOException {//創(chuàng)建數(shù)據(jù)包傳輸?shù)膶?duì)象,并綁定端口號(hào)DatagramSocket ds = new DatagramSocket(6000);//創(chuàng)建字節(jié)數(shù)組byte[] data = new byte[1024];while(true){//創(chuàng)建數(shù)據(jù)包對(duì)象,傳遞字節(jié)數(shù)組DatagramPacket dp = new DatagramPacket(data,data.length);//調(diào)用ds對(duì)象的receive接受數(shù)據(jù)包,receive()有線程阻塞效果會(huì)一直等待接受數(shù)據(jù) ds.receive(dp);//獲取數(shù)據(jù)包大小int len = dp.getLength();//獲取發(fā)送端的ip地址InetAddress sendAddress = dp.getAddress();String sendHostAddress = sendAddress.getHostAddress();//System.out.println(sendHostAddress);//獲取發(fā)送端端口號(hào)int port = dp.getPort();//System.out.println(port);//System.out.println(new String(data)); //直接打印1024個(gè)字節(jié)的字符串,有很多空格System.out.println(sendHostAddress+":"+port+" "+new String(data,0,len)); //這樣打印沒有多余的空格if(new String(data,0,len).equals("exit")){break;}}//關(guān)閉 ds.close();} }

  code

TCP

ServerSocket類,用于表示服務(wù)器端,Socket類,用于表示客戶端。建立連接后用流進(jìn)行輸入和輸出

?

ServerSocket

   實(shí)例化一個(gè)ServerSocket類,指定端口號(hào)

  監(jiān)聽并接受此套接字的連接

  返回此服務(wù)器套接字的本地地址

  Socket

  實(shí)例化一個(gè)Socket并指定ip和端口

  

返回一個(gè)輸出流,用于客戶端發(fā)送數(shù)據(jù)

  返回一個(gè)輸入流,用于服務(wù)器端接受數(shù)據(jù)

  

  返回ip地址(服務(wù)器端的地址)

  返回端口號(hào)

客戶端

1,創(chuàng)建客戶端的Socket對(duì)象,指定服務(wù)器IP和端口號(hào)

  Socket(String host, int port) ? ? ?

2,獲取Socket的輸出流對(duì)象

  getOutputStream();?

3,寫數(shù)據(jù)給服務(wù)器

  out.write("服務(wù)器數(shù)據(jù)".getBytes());

4,關(guān)閉流資源

  socket.close();

服務(wù)器端

1,創(chuàng)建服務(wù)器端ServerSocket對(duì)象,指定服務(wù)器端端口號(hào)

  ServerSocket(int port)

2,開啟服務(wù)器,等待著客戶端Socket對(duì)象的連接,如有客戶端連接,返回客戶端的Socket對(duì)象

  accept()

3,通過(guò)客戶端的Socket對(duì)象,獲取客戶端的輸入流,為了實(shí)現(xiàn)獲取客戶端發(fā)來(lái)的數(shù)據(jù)

  socket.getInputStream();

4,通過(guò)客戶端的輸入流,獲取流中的數(shù)據(jù)

byte[] data = new byte[1024];
int len = inputStream.read(data);
System.out.println(new String(data,0,len));

5,通過(guò)客戶端的Socket對(duì)象,獲取客戶端的輸出流,為了實(shí)現(xiàn)給客戶端反饋信息

6,通過(guò)客戶端的輸出流,寫數(shù)據(jù)到流中

7,關(guān)閉流資源

socket.close();
serverSocket.close();

/*** 實(shí)現(xiàn)TCP服務(wù)器程序* 表示服務(wù)器程序的類java.net.ServerSocket* 構(gòu)造方法:* ServerSocket(int port); 傳遞端口號(hào)** Important:必須獲得客戶端的套接字(Socket)* 方法:Socket accept()* 服務(wù)器可以獲取到客戶端的套接字* Created by Autumn on 2018/2/5.*/ public class TCPServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8888);//調(diào)用服務(wù)器套接字對(duì)象accept()獲取客戶端套接字,具有線程等待效果Socket socket = serverSocket.accept(); //這里會(huì)阻塞等待連接接入 cmd中telnet 127.0.0.1 8888即可連接//根據(jù)獲得的客戶端的socket獲取輸入流InputStream inputStream = socket.getInputStream();//根據(jù)輸入流將數(shù)據(jù)讀入到data中byte[] data = new byte[1024];int len = inputStream.read(data); //這里會(huì)阻塞,等待數(shù)據(jù) cmd中ctrl+]進(jìn)入到telnet操作模式send value發(fā)送數(shù)據(jù)System.out.println(new String(data,0,len));socket.close();serverSocket.close();} }/*** 實(shí)現(xiàn)TCP客戶端,連接到服務(wù)器* 和服務(wù)器實(shí)現(xiàn)數(shù)據(jù)交換* 實(shí)現(xiàn)TCP客戶端程序的類 java.net.Socket** 構(gòu)造方法:* Socket(String host, int port)傳遞服務(wù)器IP和端口號(hào)* 注意:構(gòu)造方法只要運(yùn)行,就會(huì)和服務(wù)器進(jìn)行連接,連接時(shí)報(bào),拋出異常** OutputStream getOutputStream() 返回套接字的輸出流* 作用:將數(shù)據(jù)輸出,輸出到服務(wù)器* InputStream getInputStream() 返回套接字的輸入流* 作用:從服務(wù)器端讀取數(shù)據(jù)** 客戶端服務(wù)器數(shù)據(jù)交換,必須使用套接字對(duì)象Socket中的獲取的IO劉,自己new的流不行** Created by Autumn on 2018/2/5.*/ public class TCPClient {public static void main(String[] args) throws IOException {//創(chuàng)建Socket對(duì)象,連接服務(wù)器Socket socket = new Socket("127.0.0.1",8888);//通過(guò)客戶端的套接字對(duì)象Socket方法,獲取字節(jié)輸出流,將數(shù)據(jù)寫向服務(wù)器OutputStream out = socket.getOutputStream();out.write("這是一條來(lái)客戶端的數(shù)據(jù)".getBytes());socket.close();} }

用cmd命令telnet實(shí)現(xiàn)和SocketServer互動(dòng)

import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;public class TCPServer {/*同步阻塞*/public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服務(wù)端啟動(dòng)成功...");while(true){/*一次只能處理一個(gè)連接,在一個(gè)連接沒關(guān)閉前無(wú)法接收第二個(gè)連接,在這里開一個(gè)框發(fā)送數(shù)無(wú)問(wèn)題,開放兩個(gè)框時(shí)會(huì)出現(xiàn)第二個(gè)無(wú)反應(yīng)*/Socket socket = serverSocket.accept(); //這里會(huì)阻塞等待連接接入 cmd中telnet 127.0.0.1 8888即代表連接System.out.println("新客戶端連接成功....");InputStream inputStream = socket.getInputStream();while(true) {byte[] data = new byte[1024];System.out.println("正在等待數(shù)據(jù)...");int len = inputStream.read(data); //這里會(huì)阻塞,等待數(shù)據(jù),如果直接關(guān)閉cmd窗口會(huì)因?yàn)殛P(guān)閉socket通道導(dǎo)致len返回-1 cmd中ctrl+]進(jìn)入到telnet操作模式send value發(fā)送數(shù)據(jù)if (len != -1){System.out.println(new String(data, 0,len, "GBK")); //用GBK是因?yàn)镃MD窗口命令發(fā)送的數(shù)據(jù)是GBK編碼}else{break;}}}//socket.close();//serverSocket.close();//System.out.println("服務(wù)器端關(guān)閉...."); } }

連接服務(wù)端?

向服務(wù)端發(fā)送數(shù)據(jù)

再開一個(gè)cmd然后telnet發(fā)送數(shù)據(jù),發(fā)現(xiàn)無(wú)反應(yīng)。必須關(guān)閉第一個(gè)cmd才能連接成功。

線程池改進(jìn),能并發(fā)訪問(wèn)

用ExecutorService線程池實(shí)現(xiàn)每一個(gè)連接創(chuàng)建一個(gè)新的線程

import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class TCPServer {/*異步阻塞*/public static void main(String[] args) throws IOException {ExecutorService threadPool = Executors.newCachedThreadPool(); //線程池ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服務(wù)端啟動(dòng)成功...");while(true){/*一次只能處理一個(gè)連接,在一個(gè)連接沒關(guān)閉前無(wú)法接收第二個(gè)連接,在這里開一個(gè)框發(fā)送數(shù)無(wú)問(wèn)題,開放兩個(gè)框時(shí)會(huì)出現(xiàn)第二個(gè)無(wú)反應(yīng)*/System.out.println("等待客戶端連接...");final Socket socket = serverSocket.accept(); //這里會(huì)阻塞等待連接接入 cmd中telnet 127.0.0.1 8888即代表連接threadPool.execute(new Runnable() { //啟動(dòng)一個(gè)線程public void run() {try {System.out.println("新客戶端連接成功....");InputStream inputStream = socket.getInputStream();while(true) {byte[] data = new byte[1024];System.out.println("正在等待數(shù)據(jù)...");int len = inputStream.read(data); //這里會(huì)阻塞,等待數(shù)據(jù),如果直接關(guān)閉cmd窗口會(huì)因?yàn)殛P(guān)閉socket通道導(dǎo)致len返回-1 cmd中ctrl+]進(jìn)入到telnet操作模式send value發(fā)送數(shù)據(jù)if (len != -1){System.out.println(Thread.currentThread()+new String(data, 0,len, "GBK")); //用GBK是因?yàn)镃MD窗口命令發(fā)送的數(shù)據(jù)是GBK編碼}else{System.out.println("break循環(huán)");break;}}System.out.println("一次Socket連接關(guān)閉");} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}});}//socket.close();//serverSocket.close();//System.out.println("服務(wù)器端關(guān)閉...."); } }

優(yōu)點(diǎn):傳輸質(zhì)量好(所以BIO適合傳輸連接少但是數(shù)據(jù)量大的請(qǐng)求)

缺點(diǎn):每一個(gè)連接都占用一個(gè)線程,很占用系統(tǒng)資源。

tip:所有的調(diào)優(yōu)都關(guān)聯(lián)到系統(tǒng)資源(IO、存儲(chǔ)、內(nèi)存、CPU)

code

轉(zhuǎn)載于:https://www.cnblogs.com/aeolian/p/8417916.html

總結(jié)

以上是生活随笔為你收集整理的java网络编程之Socket编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。