网络编程 UDP通信的过程 TCP通信过程 多线程文件上传
网络概述
协议
在网络之间传出数据时需要按照指定的标准来传输,标准中规定了数据的格式、大小、传输的方式、传输速率。形成统一规范—>按照规范开发的代码—>协议(应用层、传输层、网络层、链路层)
InetAddress类
用来分装网络地址:IP地址、端口、主机名称
UDP协议编程
UDP(User Datagram protocol),用户数据报协议;
特点:
- 发送端只发送数据,不管接收端是否接收数据或者接收数据是否完整
- 接受端只管接受数据
- 允许发送的数据出现丢失的现象
电视直播、广播
TCP 传输控制协议
特点:
1. 客户端:发送数据
2. 服务器:接受数据
3. 不允许出现数据丢失的情况
长传下载文件
TCP/IP的三次握手:第一次握手,客户端向服务器端发出连接请求,等待服务器确认,第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求,第三次握手,客户端再次向服务器端发送确认信息,确认连接。
UDP通信的过程
- DatagramSocket类(码头 用来存放数据包(集装箱)DatagramPacket)
- DatagramPacket类(集装箱 用来装载数据)
UDP接收端的过程
简单原理:创建一个能接收(存放)数据报(集装箱)的数据平台(码头)。
- 创建DatagramSocket(码头)来存放数据报(集装箱),这个码头要有编号(port 端口号),用来接收具有相同端口号的数据报。
- 创建有一定规格的DatagramPacket(集装箱)不需要知道是那里来的数据报。
- 接受数据报
- 读取数据报里的数据
- 关闭码头
代码
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Receive {
public static void main(String[] args)throws Exception {
//创建能存放数据报(DatagramPacket) 的 DatagramSocket(码头) 对象需指定端口号
DatagramSocket s=new DatagramSocket(6000);
//创建一个有大小的数据报对象 相当于集装箱 用来接收数据
byte []buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,1024);
//让码头接收数据报(集装箱)
s.receive(dp);
//读取集装箱里的数据
byte[] data = dp.getData();
String dataStr=new String(data);
InetAddress address = dp.getAddress();
String hostName = address.getHostName();
System.out.println(hostName);
System.out.println(dataStr);
//关闭码头 不在接收数据报(集装箱)
}
}
UDP发送端过程
简单原理:创建一个能发送数据报(集装箱)的数据平台(码头)。
- 创建能存放数据报(DatagramPacket) 的 DatagramSocket(码头) 无需指定端口号
- 创建数据报(集装箱)上要有目的地的信息、端口号等。
- 发送数据报
关闭码头
import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class Send { public static void main(String[] args) throws Exception{ //创建能存放数据报(DatagramPacket) 的 DatagramSocket(码头)无需指定端口号 DatagramSocket s=new DatagramSocket(); //创建数据报(集装箱)用来装载数据 需要指明目的地 //byte []b=new byte[1024]; byte []b="今晚七点我们在操场见面".getBytes(); DatagramPacket dp=new DatagramPacket(b, b.length, InetAddress.getByName("192.168.88.1"), 6000); //发送数据报 s.send(dp); //关闭码头 s.close(); } }
TCP通信的过程
需要注意的是:TCP通信不同于UDP通信,TCP通信需要先通过客户端连接服务器端才能实现通信,服务器不能直接连接客户端,服务器必须要先启动,等待客户端的连接。
- 客户端:Socket
- 服务器端:ServerSocket
- 先创建服务器端在创建客户端
TCP服务器端响应过程
- 创建服务器端,使用ServerSocket类,需要设置服务器的端口号
- 开启客户端连接,返回一个客户端对象
- 获得客户端发过来的信息,并输出到控制台上(输入流)
- 响应客户端的请求,给客户端发送信息(输出流)
关闭流和客户对象
import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws Exception{ //创建服务器端 使用ServerSocket 需要指定服务器的端口号 ServerSocket s=new ServerSocket(6000); //开启客户端连接 返回客户端对象 Socket socket = s.accept(); //获得客户端发过来的信息 (客户端--->写入到服务器) InputStream in = socket.getInputStream(); //控制台打印客户端发送过来的信息 int len=-1; byte []b=new byte[1024]; while((len=in.read(b))!=-1){ System.out.println(new String(b,0,len)); } //服务器响应客户端的请求 OutputStream out = socket.getOutputStream(); out.write("服务器收到".getBytes()); //关闭流 in.close(); out.close(); //关闭客户端 socket.close(); //服务器一般不关 s.close(); }
}
TCP客户端请求服务器端过程
- 创建客户端对象 指定要连接的服务器的地址和端口号
- 获得输出流对象,将要发送的数据写到服务器端
- 客户端发送数据结束标识,告诉服务器数据发送完毕
- 接受服务器响应的数据
- 关闭流
关闭客户端对象
import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class Client { public static void main(String[] args)throws Exception { //创建客户端对象并初始化要连接的服务器端的地址和端口 Socket s=new Socket("192.168.88.1",6000); //获得输出流,将数据发送给服务器 OutputStream out = s.getOutputStream(); out.write("嗨,我是客户端 ".getBytes()); //给服务器标识 客户端已经完成了数据的发送 s.shutdownOutput(); //接受服务器返回来的信息 InputStream in = s.getInputStream(); int len=-1; byte[] b=new byte[1024]; while((len=in.read(b))!=-1){ System.out.println(new String(b,0,len)); } //关闭流 out.close(); in.close(); //关闭客户端 s.close(); } }
多线程文件上传练习
服务器端
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 多线程实现文件上传
*
* @author YandeHu
*
*/
public class Server {
public static void main(String[] args) throws Exception {
// 创建服务器端 ServerSocket类 设置端口号
ServerSocket s = new ServerSocket(6000);
while (true) {
// 创建客户对象 开启客户端连接
final Socket socket = s.accept();
// 创建线程匿名内部类
new Thread() {
@Override
public void run() {
try {
// 客户端获取输入流对象将客户端的消息显示出来
InputStream in = socket.getInputStream();
// 创建文件输出流
FileOutputStream fos = new FileOutputStream(System.currentTimeMillis() + ".jpg");
int len = -1;
byte[] b = new byte[1024];
while ((len = in.read(b)) != -1) {
fos.write(b);
}
// 响应客户端
OutputStream out = socket.getOutputStream();
out.write("文件上传成功".getBytes());
// 关闭流
in.close();
fos.close();
out.close();
// 关闭客户端
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
客户端
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args)throws Exception {
//创建客户端类
Socket s=new Socket("192.168.88.1",6000);
//创建文件输入流
FileInputStream fis=new FileInputStream("E:\\微信、ps素材\\微信素材文件\\图片素材\\爱情.jpg");
//获取输出流
OutputStream out = s.getOutputStream();
int len=-1;
byte[]b=new byte[1024];
while((len=fis.read(b))!=-1){
out.write(b,0,len);
}
//设置标记 标记上传文件结束
s.shutdownOutput();
//获得服务器响应的信息
InputStream in = s.getInputStream();
int len1=-1;
byte[]n=new byte[1024];
while((len1=in.read(n))!=-1){
System.out.println(new String(n,0,len1));
}
//关闭流
fis.close();
out.close();
in.close();
//关闭客户端
s.close();
}
}