計(jì)算機(jī)網(wǎng)絡(luò)
是指將地理位置不同的具有獨(dú)立功能的多臺計(jì)算機(jī)及其外部設(shè)備,通過通信線路連接起來,在網(wǎng)絡(luò)操作系統(tǒng),網(wǎng)絡(luò)管理軟件及網(wǎng)絡(luò)通信協(xié)議的管理和協(xié)調(diào)下,實(shí)現(xiàn)資源共享和信息傳遞的計(jì)算機(jī)系統(tǒng)。包括局域網(wǎng)(intranet)和廣域網(wǎng)(internet)
網(wǎng)絡(luò)模型
網(wǎng)絡(luò)模型一般是指
○ OSI(Open System Interconnection開放系統(tǒng)互連)參考模型
○ TCP/IP參考模型
網(wǎng)絡(luò)編程 就是用來實(shí)現(xiàn)網(wǎng)絡(luò)互聯(lián)的不同計(jì)算機(jī)上運(yùn)行的程序間可以進(jìn)行數(shù)據(jù)交換。
計(jì)算機(jī)網(wǎng)絡(luò)之間以何種規(guī)則進(jìn)行通信,就是網(wǎng)絡(luò)模型研究問題
客戶機(jī)服務(wù)器模式(Client/Server)
●為了實(shí)現(xiàn)兩臺計(jì)算機(jī)的通信,必須要用一個(gè)網(wǎng)絡(luò)線路連接兩臺計(jì)算機(jī)。
● 服務(wù)器(Server)是指提供信息的計(jì)算機(jī)或程序
●客戶機(jī)(Client)是指請求信息的計(jì)算機(jī)或程序
●網(wǎng)絡(luò)用于連接服務(wù)器與客戶機(jī),實(shí)現(xiàn)兩者相互通信。
TCP/IP的概念和實(shí)現(xiàn)
TCP/IP:Transmission Control Protocol/Internet Protocol的簡寫。TCP 是傳輸控制協(xié)議的縮寫,它保障了兩個(gè)應(yīng)用程序之間的可靠通信。通常用于互聯(lián)網(wǎng)協(xié)議,被稱 TCP / IP。
TCP三次握手(Three-way handshake)
所謂的“三次握手”即對每次發(fā)送的數(shù)據(jù)量是怎樣跟蹤進(jìn)行協(xié)商使數(shù)據(jù)段的發(fā)送和接收同步,根據(jù)所接收到的數(shù)據(jù)量而確定的數(shù)據(jù)確認(rèn)數(shù)及數(shù)據(jù)發(fā)送、接收完畢后何時(shí)撤消聯(lián)系,并建立連接。
? 第一次握手:建立連接時(shí),客戶端發(fā)送syn包(syn=j)到服務(wù)器,并進(jìn)入SYN_SENT狀態(tài),等待服務(wù)器確認(rèn);
SYN:同步序列編號(Synchronize Sequence Numbers)。
? 第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(seq=k),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
? 第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ETABLISHED(TCP連接成功)狀態(tài),完成三次握手。
? 完成三次握手,客戶端與服務(wù)器開始傳送數(shù)據(jù)
TCP編程
套接字(Socket)是使用TCP提供了兩臺計(jì)算機(jī)之間的通信機(jī)制。
客戶端程序創(chuàng)建一個(gè)套接字,并嘗試連接服務(wù)器的套接字。
當(dāng)連接建立時(shí),服務(wù)器會創(chuàng)建一個(gè) Socket 對象。客戶端和服務(wù)器現(xiàn)在可以通過對
Socket 對象的寫入和讀取來進(jìn)行通信。
? 服務(wù)端:
創(chuàng)建服務(wù)端對象,監(jiān)聽一個(gè)端口
ServerSocket ss = new ServerSocket(100);
獲取客戶端對象
Socket s = ss.accept(); String ip = s.getInetAddress().getHostAddress();
? 客戶端:
創(chuàng)建客戶端socket服務(wù),把ip和端口作為地址傳進(jìn)構(gòu)造函數(shù)
Socket s = new Socket("localhost",100);
UDP的概念和實(shí)現(xiàn)
UDP(User Datagram Protocol):UDP 是用戶數(shù)據(jù)報(bào)協(xié)議的縮寫,一個(gè)無連接的協(xié)議。提供了應(yīng)用程序之間要發(fā)送的數(shù)據(jù)的數(shù)據(jù)包。
用戶數(shù)據(jù)包協(xié)議(UDP)是網(wǎng)絡(luò)信息傳輸?shù)牧硪环N形式,基于UDP的通信與基于TCP的通信不同,UDP的信息傳遞更快,但不提供可靠的保證。
UDP編程
發(fā)送端:
建立udp服務(wù),發(fā)送端沒有指定端口,會自動分配一個(gè)端口
DatagramSocket ds = new DatagramSocket();
定義數(shù)據(jù)內(nèi)容,并將數(shù)據(jù)封裝成包
byte[] bt = “hello,udp,我來了”.getBytes();
把要發(fā)送的數(shù)據(jù)和ip、port封裝到數(shù)據(jù)包里
DatagramPacket db = new
DatagramPacket(bt,bt.length,InetAddress.getByName(“192.168.1.105”),10000);
通過udp的socket服務(wù)中的功能完成數(shù)據(jù)包的發(fā)送 ds.send(db);
接收端:定義socket服務(wù),監(jiān)聽端口
DatagramSocket ds = new DatagramSocket(10000);
預(yù)先定義好一個(gè)數(shù)據(jù)包,用于存儲接收到的數(shù)據(jù)
byte[] bt = new byte[1024];
創(chuàng)建數(shù)據(jù)包對象,用于接收數(shù)據(jù)
DatagramPacket dp = new
DatagramPacket(bt,bt.length);
使用socket服務(wù)的receive方法將接受到的數(shù)據(jù)存儲到數(shù)據(jù)包中
ds.receive(dp);
通過數(shù)據(jù)包對象,獲取數(shù)據(jù)包內(nèi)容
byte[] data = dp.getData();
String ip = dp.getAddress().getHostAddress();
int port = dp.getPort();
TCP和UDP的區(qū)別
TCP:
1,面向連接的協(xié)議,在socket之間進(jìn)行數(shù)據(jù)傳輸之前必然要建立連接,所以在TCP中需要連接時(shí)間。
2,TCP傳輸數(shù)據(jù)無大小限制,一旦連接建立起來,雙方的socket就可以按統(tǒng)一的格式傳輸大的數(shù)據(jù)。
3,TCP是一個(gè)可靠的協(xié)議,它確保接收方完全正確地獲取發(fā)送方所發(fā)送的全部數(shù)據(jù)。
UDP:
1,每個(gè)數(shù)據(jù)報(bào)中都給出了完整的地址信息,因此無需要建立發(fā)送方和接收方的連接。
2,UDP傳輸數(shù)據(jù)時(shí)是有大小限制的,每個(gè)被傳輸?shù)臄?shù)據(jù)報(bào)必須限定在64KB之內(nèi)。
3,UDP是一個(gè)不可靠的協(xié)議,發(fā)送方所發(fā)送的數(shù)據(jù)報(bào)并不一定以相同的次序到達(dá)接收方
TCP和UDP最大的區(qū)別在于是否需要客戶端與服務(wù)端建立連接后才能進(jìn)行數(shù)據(jù)傳輸。
聊天室
服務(wù)器處理線程
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Reader; import java.net.Socket; import java.net.SocketException; import java.util.Scanner; public class ServerTask implements Runnable{ private Socket socket; public ServerTask(Socket socket) { // TODO 自動生成的構(gòu)造函數(shù)存根 this.socket = socket; } @Override public void run() { // TODO 自動生成的方法存根 //建立通信后所執(zhí)行的內(nèi)容 System.out.println("歡迎【"+socket.getRemoteSocketAddress().toString()+"】進(jìn)入聊天室"); //構(gòu)建讀取緩沖 BufferedReader br =null; //http響應(yīng)寫入 PrintWriter pw = null; try { //獲取客戶端輸入的信息 字節(jié)流緩沖成字符流 br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String msg; while((msg=br.readLine()) != null) { msg = "【"+socket.getRemoteSocketAddress().toString()+"】說"+msg; //輸出客戶端信息 System.out.println(msg); //服務(wù)器接收到客戶端的消息發(fā)送消息給客戶端 Scanner scanner = new Scanner(System.in); System.out.println("請輸入要發(fā)送的信息!"); pw = new PrintWriter(socket.getOutputStream(),true); pw.println("服務(wù)器說:"+scanner.nextLine()); pw.flush(); } }catch (SocketException e) { // TODO: handle exception System.out.println(socket.getRemoteSocketAddress().toString()+"退出聊天室!"); } catch (Exception e) { // TODO: handle exception } } }
客戶端處理線程
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.net.Socket; import java.net.SocketException; import java.util.Scanner; public class ClientTask implements Runnable{ private Socket socket; public ClientTask(Socket socket) { // TODO 自動生成的構(gòu)造函數(shù)存根 this.socket = socket; } @Override public void run() { // TODO 自動生成的方法存根 try { while(true) { Scanner scanner = new Scanner(System.in); System.out.println("請輸入要發(fā)送的信息"); //消息發(fā)送到服務(wù)器 PrintWriter pw = new PrintWriter(socket.getOutputStream(),true); //br.readLine()讀取的消息發(fā)送到服務(wù)器 pw.println(scanner.nextLine()); //讀取服務(wù)器發(fā)送的消息 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); System.out.println(br.readLine()); } } catch (Exception e) { // TODO: handle exception } } }
服務(wù)器
import java.net.ServerSocket; import java.net.Socket; import com.qingsu.chat.Task.ServerTask; public class ChatServer { public static void main(String[] args) { try { //創(chuàng)建服務(wù)端對象 監(jiān)聽一個(gè)窗口 ServerSocket serverSocket = new ServerSocket(10622); System.out.println("服務(wù)器創(chuàng)建成功!端口號"+10622); //阻塞 直到有鏈接返回 while(true) { Socket socket = serverSocket.accept();//獲取客戶端對象 //啟動一個(gè)線程處理該鏈接 Thread thread = new Thread(new ServerTask(socket)); thread.start(); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }
客戶端
import java.net.Socket; import com.qingsu.chat.Task.ClientTask; public class ChatClient { public static void main(String[] args) { try { //創(chuàng)建客戶端socket服務(wù),把ip和端口作為地址傳進(jìn)構(gòu)造函數(shù) Socket socket = new Socket("127.0.0.1",10622); //啟動客戶機(jī)線程處理 Thread thread = new Thread(new ClientTask(socket)); thread.start(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }
效果
到此這篇關(guān)于Java 全面掌握網(wǎng)絡(luò)編程篇的文章就介紹到這了,更多相關(guān)Java 網(wǎng)絡(luò)編程內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/Carryi/article/details/120730448