網路編程 TCP 編程 使用tcp 之前先建立TCP連接,形成傳輸數據的通道,點對點的通信是可靠的。 2,兩個進程:客戶端 服務端 3,在連接中進行大量數據的傳輸 4,傳輸完畢需要釋放建立的連接,效率較低 客戶端: 1,創建socket對象,指明伺服器端的ip和埠。 2,獲取一個輸出流用於向伺服器 ...
網路編程
TCP 編程
使用tcp 之前先建立TCP連接,形成傳輸數據的通道,點對點的通信是可靠的。
2,兩個進程:客戶端 服務端
3,在連接中進行大量數據的傳輸
4,傳輸完畢需要釋放建立的連接,效率較低
客戶端:
1,創建socket對象,指明伺服器端的ip和埠。
2,獲取一個輸出流用於向伺服器端寫入數據。
3,寫出數據
4,關閉資源
UDP
類似於發電報,發出去就完事了!
將數據源封裝成數據包,不需要建立連接,每個數據包大小限制在64k內
數據包:(datagram)網路傳輸的基本單位
我們需要實現的是由客戶端發送數據伺服器接收到數據後響應給客戶端表示已成功接收
我們可以由client端寫起:
首先我們需要確定發送的位置即需要ip port 用Socket 封裝
需要一個輸出流向伺服器寫入數據
然後是伺服器:
伺服器有 ServerSocket 指定埠,然後 socket = ss.accept(); 接收;需要一個輸入流來讀取客戶端的內容,接收完成後向客戶端發一個數據表示已經接收到了數據,然後在客戶端列印
package com.kobedu.demo;
import org.junit.Test;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/**
* 實現TCP網路編程
* 從客戶端發送文件給伺服器,服務端將文件保存到本地並 返回“發送成功”到客戶端。
* 並關閉相應的連接
*/
public class Example3 {
/**
* 客戶端:首先我們不難想到,你是要從客戶端向伺服器發數據的,所以
* 你得唯一確定一臺伺服器,一個伺服器上又不止一個進程,是多個進程同時在跑的
* 所以你也要唯一確定進程,也就是說需要ip port
* 用socket 套接字封裝ip port
* 就可以唯一確定你發數據的地點
*/
@Test
public void client(){
InputStream is = null;
InetAddress inet = null;
Socket socket = null;
//需要向伺服器寫入
OutputStream os = null;
ByteArrayOutputStream bao = null;
try {
//ip 對應著InetAddress 類的一個對象
inet = InetAddress.getByName("localhost");
//創建了套接字對象,指明瞭伺服器的ip port
socket = new Socket(inet,1024);
// 用於向伺服器寫入數據的輸出流
os = socket.getOutputStream();
//is 位元組輸入流用於從文件中讀取
is = new FileInputStream("picture/nr1.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer);
}
//相當於告訴了伺服器他不用等已經沒數據傳了
socket.shutdownOutput();
//接收來自伺服器端的反饋,並顯示在控制台
is = socket.getInputStream();
bao = new ByteArrayOutputStream();
int len2;
byte[] buff2 = new byte[3];
while((len2 = is.read(buff2))!= -1){
bao.write(buff2,0,len2);
}
System.out.println(bao.toString());
} catch (Exception e) {
e.printStackTrace();
}finally {
if (is!=null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket!=null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os!=null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bao!=null) {
try {
bao.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void server(){
ServerSocket ss = null;
Socket socket = null;
InputStream is = null;
OutputStream os = null;
OutputStream os2 = null;
try {
ss = new ServerSocket(1024);
socket = ss.accept();
is = socket.getInputStream();
os = new FileOutputStream("picture/gril2.jpg");
byte[] buff = new byte[1024];
int len ;
while (((len = is.read(buff)) != -1)) {
os.write(buff,0,len);
}
System.out.println("伺服器已成功接收數據!");
// 伺服器端給客戶端反饋,是否收到
os2 = socket.getOutputStream();
os2.write("照片我已收到,很漂亮,我很滿意!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
if (os!=null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is!=null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket!=null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ss!=null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os2!=null) {
try {
os2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
由上面的圖片可以看出在實現在服務端接收完畢後反饋給客戶端時會出現上面的問題,就是C S 都一直啟動,在關閉時才有數據的接收成功,結合下圖可以看出程式停在某個部分,下麵一框出,出現這種問題是因為在這種情況下,客戶端並未給伺服器說他傳完了,伺服器傻傻地等就出現了這種情況
UDP
udp 編程從技術的角度上講並不像tcp那樣有嚴格意義上的客戶端與服務端,在電腦網路中學過關於網路編程的相關內容udp和tcp都是傳輸層協議,tcp 在端系統之間的通信是可靠的,tcp會事先建立好連接,將要發送的數據包編號,f發的時候會在本地存一份,以防發送失敗,重新發送,所以tcp編程的通信是可靠的但是這種可靠是需要犧牲時間為代價,在電腦網路中深入理解tcp和udp編程後就不難發現,tcp的事先的連接,給數據編號,連接的釋放,在發送端將數據緩存,以防在發送的途中丟失數據,重發。他們各有千秋
@Test
public void sender(){
DatagramSocket socket = null;
DatagramPacket packet = null;
InetAddress inet = null;
try {
//
socket = new DatagramSocket();
String str = "這是以UDP的方式發送數據";
byte[] bytes = str.getBytes();
inet = InetAddress.getByName("localhost");//目標地
packet = new DatagramPacket(bytes,0,bytes.length,inet,1024);
//發送數據
socket.send(packet);
} catch (Exception e) {
e.printStackTrace();
}finally {
if (socket !=null) {
socket.close();
}
}
}
在上面的代碼中我們可以和tcp 編程做比較,這裡並沒有向tcp那樣,在客戶端有輸出流向伺服器端寫出數據,而是由DatagramPacket 封裝要發送的數據。用套接字的send的方法發送,
@Test
public void receiver(){
DatagramSocket socket = null;
DatagramPacket datagramPacket = null;
try {
socket = new DatagramSocket(1024);
byte[] bytes = new byte[100];
datagramPacket = new DatagramPacket(bytes,0,bytes.length);
//接收數據
socket.receive(datagramPacket);
System.out.println(new String(datagramPacket.getData(),0, datagramPacket.getLength()));
} catch (Exception e) {
e.printStackTrace();
}finally {
if (socket != null) {
socket.close();
}
}
}
套接字
相當於是一個門,。。。
補充:
Tcp 是面向連接到的保證可靠的傳輸協議;通過tcp協議可以得到一個順序誤差錯的數據流,一旦這兩個socket建立起了連接,他們就可以進行雙向的數據傳輸;
udp是一種無連接的協議,每個數據報都是一個獨立的信息,包括完整的源地址,目標地址;
udp 傳輸數據時是有大小限制的,每個傳輸的數據報必須要限定在64kb之內;
jdk 中的網路類
無論你是在打電話、發送郵件或建立與Internet的連接,地址是基礎。 InetAddress類用來封裝我們前面討論的數字式的IP地址和該地址的功能變數名稱。你通過一個IP主機名與這個類發生作用, IP主機名比它的IP地址用起來更簡便更容易理解。
InetAddress 類內部隱藏了地址數字。
工廠方法
– InetAddress 類沒有明顯的構造函數。為生成一個InetAddress對象,必須運用一個可用的工廠方法。
– 工廠方法(factory method)僅是一個類中靜態方法返回一個該類實例的約定。對於InetAddress,三個方法 getLocalHost( )、getByName( )以及getAllByName( )可以用來創建InetAddress的實例
getLocalHost();方法返回象徵本地主機的InetAddress對象;
getByName();返回一個傳給它的主機名的InetAddress。
getAllByName();返回傳入名稱匹配的所有地址類數組;
UDP 編程補充
1,什麼是Datagram? ——數據報是網上傳輸的獨立的數據包,數據報是能夠正確地到達目的地,到達的時間,順序,內容的完整性是沒有保證的;
2,