勿以惡小而爲之,勿以善小而不爲--------------------------劉備
勸諸君,多行善事積福報,莫作惡
上一章簡單介紹了 InetAddress和爬蟲簡單應用(一),如果沒有看過,請觀看上一章
網絡通信,是 C/S 模式,需要編寫 客戶端和服務器端的代碼, 服務器端需要指定端口號, 客戶端需要指定 服務器的ip地址和端口號,這樣才能保持連接通信, 網絡通信,需要先開啓服務端,才能啓動客戶端。
還需要了解一點, 客戶端的輸入,連接的是服務器端的輸出, 客戶端的輸出,連接的是服務器端的輸入。
一. UDP 通信所需要用到的類
一.一 DatagramSocket 類
這是服務器端的類, 需要指定接口。
一.一.一 構造方法
一.一.一.一 方法
方法 | 作用 |
---|---|
DatagramSocket(int port) | 本機的某個端口 |
DatagramSocket(int port, InetAddress laddr) | 某個指定主機的某個端口 |
一.一.一.二 演示
@Test
public void conTest(){
try {
//綁定的是本機
DatagramSocket datagramSocket=new DatagramSocket(9999);
} catch (SocketException e) {
e.printStackTrace();
}
try {
//綁定到指定的服務器
InetAddress inetAddress=InetAddress.getByName("localhost");
DatagramSocket datagramSocket=new DatagramSocket(9999,inetAddress);
} catch (UnknownHostException e) {
e.printStackTrace();
}catch (SocketException e) {
e.printStackTrace();
}
}
一.一.二 其他常用方法
方法 | 作用 |
---|---|
void close() | 關閉 |
void send(DatagramPacket p) | 發送數據 |
void receive(DatagramPacket p) | 接收數據 |
發送時和接收數據時,發送和接收的是一個對象, DatagramPacket, 這個對象裏面封裝了真正的通信數據。
一.二 DatagramPacket
數據封裝包。
一.二.一 構造方法
一.二.一.一 方法
方法 | 作用 |
---|---|
DatagramPacket(byte[] buf, int offset, int length) | 從客戶端接收數據,將offset到offset+len的數據,放置到 字節數組裏面 |
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) | 將字節數組數據發送到服務器 |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) | 將字節數組數據發送到服務器 |
一.二.一.二 演示
@Test
public void packetConTest(){
//定義的是byte 字節
byte[] bytes=new byte[1024];
//第一種,從客戶端接收數據
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,1024);
InetAddress inetAddress= null;
try {
inetAddress = InetAddress.getByName("localhost");
} catch (UnknownHostException e) {
e.printStackTrace();
}
//第二種,接收固定 主機
DatagramPacket datagramPacket1=new DatagramPacket(bytes,0,1024,inetAddress,6666);
//第三種, 在客戶端發送數據到服務器端
DatagramPacket datagramPacket2=new DatagramPacket(bytes,0,1024,new InetSocketAddress("localhost",6666));
}
一.二.二 其他方法
方法 | 作用 |
---|---|
byte[] getData() | 獲取客戶端發送過來的真實數據 |
int getLength() | 獲取客戶端發送過來的數據的長度 |
int getOffset() | 獲取偏移量 |
getPort() | 獲取端口號 |
InetAddress getAddress() | 獲取裏面的 inetAddress對象 |
二. 演示各種 UDP 通信
二.一 單條字符串數據
二.一.一 客戶端
@Test
public void send1Test() throws Exception{
//1. 定義客戶端
System.out.println("------------發送方開始發送單條數據--------------");
//客戶端端口
DatagramSocket datagramSocket=new DatagramSocket(6666);
//2. 準備數據
String content="你好啊,我是兩個蝴蝶飛";
//3. 將數據轉換成字節數據
byte[] bytes=content.getBytes("UTF-8");
//4. 封裝進包
InetAddress inetAddress=InetAddress.getByName("localhost");
//服務器爲 localhost,端口爲 9999
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length,inetAddress,9999);
//發送數據
datagramSocket.send(datagramPacket);
//關閉流
datagramSocket.close();
}
二.一.二 服務器端
@Test
public void send1Test() throws Exception{
//1. 定義服務器
System.out.println("---------------服務器啓動成功,接收單條數據----------------");
DatagramSocket datagramSocket=new DatagramSocket(9999);
//2. 設置數據,封裝到 bytes字節數據, 這個數組可能是不夠用的。
byte[] bytes=new byte[1024];
//能接收的大小,並不是實際接收的大小
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length);
//3. 阻塞式接收傳遞過來的數據
datagramSocket.receive(datagramPacket);
//4. 獲取接收的數據, 是真實的數據。
byte[] content=datagramPacket.getData();
int len=datagramPacket.getLength();
System.out.println("接收的長度是:"+len+",接收的內容是:"+new String(content,0,len));
//5 關閉流
datagramSocket.close();
}
二.一.三 運行程序
先打開服務器端,
一直在阻塞式接收客戶端
再打開客戶端
這個時候,再查看一下服務器端
二.二 發送多條不同類型的數據
二.二.一 客戶端
@Test
public void send2Test() throws Exception{
//1. 定義客戶端
System.out.println("------------發送方開始發送多條數據--------------");
DatagramSocket datagramSocket=new DatagramSocket(6666);
//2. 準備數據
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
//封裝數據
DataOutputStream dataOutputStream=new DataOutputStream(new BufferedOutputStream(byteArrayOutputStream));
dataOutputStream.writeUTF("兩個蝴蝶飛");
dataOutputStream.writeInt(24);
dataOutputStream.writeDouble(95.5);
dataOutputStream.writeChar('男');
dataOutputStream.writeUTF("一個快樂的程序員");
//一定不要忘記刷新
dataOutputStream.flush();
//3. 將數據轉換成字節數據
byte[] bytes=byteArrayOutputStream.toByteArray();
// System.out.println("發送數據爲:"+new String(bytes));
//4. 封裝進包
InetSocketAddress inetSocketAddress=new InetSocketAddress("localhost",9999);
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length,inetSocketAddress);
datagramSocket.send(datagramPacket);
//關閉流
datagramSocket.close();
}
二.二.二 服務端
@Test
public void send2Test() throws Exception{
//1. 定義服務器
System.out.println("---------------服務器啓動成功,接收多條數據----------------");
DatagramSocket datagramSocket=new DatagramSocket(9999);
//2. 設置數據
byte[] bytes=new byte[1024];
//能接收的大小,並不是實際接收的大小
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length);
//3. 阻塞式接收傳遞過來的數據
datagramSocket.receive(datagramPacket);
//4. 獲取接收的數據
byte[] content=datagramPacket.getData();
int len=datagramPacket.getLength();
// System.out.println("數據是:"+ new String(content,0,content.length)+",長度是:"+len);
//將數據放置到內存裏面
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(content);
DataInputStream dataInputStream=new DataInputStream(new BufferedInputStream(byteArrayInputStream));
//讀取數據
String name=dataInputStream.readUTF();
int age=dataInputStream.readInt();
double score=dataInputStream.readDouble();
char sex=dataInputStream.readChar();
String desc=dataInputStream.readUTF();
System.out.printf("姓名是:%s,年齡是:%d,成績是:%f,性別是:%c,描述是:%s",name,age,score,sex,desc);
//5 關閉流
datagramSocket.close();
}
二.二.三 運行程序
運行服務器端, 後運行客戶端, 查看服務器端數據輸出:
二.三 發送對象數據
有一個 Person 類, 還是具有 id,name,sex,age,desc 等屬性
二.三.一 客戶端
@Test
public void send3Test() throws Exception{
//1. 定義客戶端
System.out.println("------------發送方開始發送對象數據--------------");
DatagramSocket datagramSocket=new DatagramSocket(6666);
//2. 準備數據
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new BufferedOutputStream(byteArrayOutputStream));
//放入對象
Person person=new Person();
person.setId(1);
person.setName("兩個蝴蝶飛");
person.setSex('男');
person.setAge(24);
person.setDesc("一個快樂的程序員");
objectOutputStream.writeObject(person);
//放置日期
objectOutputStream.writeObject(new Date());
//一定不要忘記刷新
objectOutputStream.flush();
//3. 將數據轉換成字節數據
byte[] bytes=byteArrayOutputStream.toByteArray();
// System.out.println("發送數據爲:"+new String(bytes));
//4. 封裝進包
InetSocketAddress inetSocketAddress=new InetSocketAddress("localhost",9999);
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length,inetSocketAddress);
datagramSocket.send(datagramPacket);
//關閉流
datagramSocket.close();
}
二.三.二 服務器端
@Test
public void send3Test() throws Exception{
//1. 定義服務器
System.out.println("---------------服務器啓動成功,接收對象數據----------------");
DatagramSocket datagramSocket=new DatagramSocket(9999);
//2. 設置數據
byte[] bytes=new byte[1024];
//能接收的大小,並不是實際接收的大小
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length);
//3. 阻塞式接收傳遞過來的數據
datagramSocket.receive(datagramPacket);
//4. 獲取接收的數據
byte[] content=datagramPacket.getData();
int len=datagramPacket.getLength();
//將數據放置到內存裏面
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(content);
ObjectInputStream objectInputStream=new ObjectInputStream(new BufferedInputStream(byteArrayInputStream));
//讀取數據
Object obj1=objectInputStream.readObject();
if(obj1 instanceof Person){
Person person=(Person)obj1;
System.out.println(person.toString());
}else{
System.out.println("接收格式有誤");
}
Object obj2=objectInputStream.readObject();
if(obj2 instanceof Date){
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
System.out.println("日期:"+sdf.format((Date)obj2));
}else{
System.out.println("接收格式有誤");
}
//5 關閉流
datagramSocket.close();
}
二.三.三 運行程序
運行服務器端, 後運行客戶端, 查看服務器端數據輸出:
二.四 發送圖片文件
### 二.四.一 文件工具類 IOUtils
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
*1、 圖片讀取到字節數組
*2、 字節數組寫出到文件
* @author 兩個蝴蝶飛
*
*/
public class IOUtils {
/**
* 1、文件,一般爲圖片 讀取到字節數組
* 1)、圖片到程序 FileInputStream
* 2)、程序到字節數組 ByteArrayOutputStream
*/
public static byte[] fileToByteArray(String filePath) {
//1、創建源與目的地
File src = new File(filePath);
byte[] dest =null;
//2、選擇流
InputStream is =null;
ByteArrayOutputStream baos =null;
try {
is =new FileInputStream(src);
baos = new ByteArrayOutputStream();
//3、操作 (分段讀取)
byte[] flush = new byte[1024*10]; //緩衝容器
int len = -1; //接收長度
while((len=is.read(flush))!=-1) {
baos.write(flush,0,len); //寫出到字節數組中
}
baos.flush();
return baos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//4、釋放資源
try {
if(null!=is) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* 2、字節數組寫入到文件
* 1)、字節數組到程序 ByteArrayInputStream
* 2)、程序到文件 FileOutputStream
*/
public static void byteArrayToFile(byte[] src,String filePath) {
//1、創建源
File dest = new File(filePath);
//2、選擇流
InputStream is =null;
OutputStream os =null;
try {
is =new ByteArrayInputStream(src);
os = new FileOutputStream(dest);
//3、操作 (分段讀取)
byte[] flush = new byte[5]; //緩衝容器
int len = -1; //接收長度
while((len=is.read(flush))!=-1) {
os.write(flush,0,len); //寫出到文件
}
os.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
//4、釋放資源
try {
if (null != os) {
os.close();
}
} catch (Exception e) {
}
}
}
}
二.四.二 客戶端
@Test
public void send4Test() throws Exception{
//1. 定義客戶端
System.out.println("------------發送方開始發送圖片文件數據--------------");
DatagramSocket datagramSocket=new DatagramSocket(6666);
//2. 準備數據
//3. 將數據轉換成字節數據
String path="E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"129.png";
byte[] bytes= IOUtils.fileToByteArray(path);
// System.out.println("發送數據爲:"+new String(bytes));
//4. 封裝進包
InetSocketAddress inetSocketAddress=new InetSocketAddress("localhost",9999);
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length,inetSocketAddress);
datagramSocket.send(datagramPacket);
//關閉流
datagramSocket.close();
}
二.四.三 服務器端
@Test
public void send4Test() throws Exception{
//1. 定義服務器
System.out.println("---------------服務器啓動成功,接收圖片文件數據----------------");
DatagramSocket datagramSocket=new DatagramSocket(9999);
//2. 設置數據
byte[] bytes=new byte[1024*20];
//能接收的大小,並不是實際接收的大小
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length);
//3. 阻塞式接收傳遞過來的數據
datagramSocket.receive(datagramPacket);
//4. 獲取接收的數據
byte[] content=datagramPacket.getData();
int len=datagramPacket.getLength();
String path="E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"129Udp.png";
IOUtils.byteArrayToFile(content,path);
//5 關閉流
datagramSocket.close();
}
二.四.四 運行程序
運行服務器端, 後運行客戶端, 查看文件系統
二.五 控制檯輸入單條數據
二.五.一 客戶端
public static void main(String[] args) {
try {
send5Test();
//send6Test();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void send5Test() throws Exception{
//1. 定義客戶端
System.out.println("------------發送方開始發送控制檯打印數據--------------");
DatagramSocket datagramSocket=new DatagramSocket(6666);
//2. 準備數據
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));
String content=bufferedReader.readLine();
byte[] bytes=content.getBytes("UTF-8");
// System.out.println("發送數據爲:"+new String(bytes));
//4. 封裝進包
InetSocketAddress inetSocketAddress=new InetSocketAddress("localhost",9999);
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length,inetSocketAddress);
datagramSocket.send(datagramPacket);
//關閉流
datagramSocket.close();
}
二.五.二 服務器端
@Test
public void send5Test() throws Exception{
//1. 定義服務器
System.out.println("---------------服務器啓動成功,接收控制檯數據----------------");
DatagramSocket datagramSocket=new DatagramSocket(9999);
//2. 設置數據
byte[] bytes=new byte[1024];
//能接收的大小,並不是實際接收的大小
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length);
//3. 阻塞式接收傳遞過來的數據
datagramSocket.receive(datagramPacket);
//4. 獲取接收的數據
byte[] content=datagramPacket.getData();
int len=datagramPacket.getLength();
System.out.println("接收的內容是:"+new String(content,0,len));
datagramSocket.close();
}
二.五.三 運行程序
先運行服務器端,
運行客戶端,輸入要打印的數據
再次查看服務器端
二.六 控制檯輸入多條數據
需要用 循環進行創建。
二.六.一 客戶端
public static void send6Test() throws Exception{
//1. 定義客戶端
System.out.println("------------發送方開始發送控制檯多條數據--------------");
DatagramSocket datagramSocket=new DatagramSocket(6666);
//2. 準備數據
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));
while(true){
String content=bufferedReader.readLine();
byte[] bytes=content.getBytes("UTF-8");
// System.out.println("發送數據爲:"+new String(bytes));
//4. 封裝進包
InetSocketAddress inetSocketAddress=new InetSocketAddress("localhost",9999);
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length,inetSocketAddress);
datagramSocket.send(datagramPacket);
if("bye".equalsIgnoreCase(content)||"quit".equalsIgnoreCase(content)){
System.out.println("退出程序");
break;
}
}
//關閉流
datagramSocket.close();
}
二.六.二 服務器端
@Test
public void send6Test() throws Exception{
//1. 定義服務器
System.out.println("---------------服務器啓動成功,接收控制檯多條數據----------------");
DatagramSocket datagramSocket=new DatagramSocket(9999);
//2. 設置數據
byte[] bytes=new byte[1024];
while(true){
//能接收的大小,並不是實際接收的大小
DatagramPacket datagramPacket=new DatagramPacket(bytes,0,bytes.length);
//3. 阻塞式接收傳遞過來的數據
datagramSocket.receive(datagramPacket);
//4. 獲取接收的數據
byte[] content=datagramPacket.getData();
int len=datagramPacket.getLength();
String temp=new String(content,0,len);
if("bye".equalsIgnoreCase(temp)||"quit".equalsIgnoreCase(temp)){
break;
}
System.out.println("echo:"+temp);
}
datagramSocket.close();
}
二.六.三 運行程序
運行服務器,再運行客戶端
服務器端
謝謝您的觀看,如果喜歡,請關注我,再次感謝 !!!