勿以恶小而为之,勿以善小而不为--------------------------刘备
劝诸君,多行善事积福报,莫作恶
上一章简单介绍了 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();
}
二.六.三 运行程序
运行服务器,再运行客户端
服务器端
谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!