1、使用基于UDP协议的Socket网络编程实现
2、不需要利用I0流实现数据的传输
3、每个数据发送单元被统一封装成数据包的方式,发送方将数据包发送到网络中,数据包在网络中去寻找他的目的地
发送数据一般不超过60K,比如微信发消息
步骤1、用DatagramSocket制定端口,创建接收端
步骤2、准备容器,封装成DatagramPacket包裹
步骤3、阻塞式接收报包receive(DatagramPacket p)
步骤4、分析数据:
getData()
getLength()
步骤5、释放资源
public class UdpServer {
public static void main(String[] args) throws Exception {
System.out.println("接收方启动中...");
// 1、用DatagramSocket制定端口,创建接收端
DatagramSocket server=new DatagramSocket(9999);
// 2、准备容器,封装成DatagramPacket包裹
byte[] container=new byte[1024*60]; //容器最大为60K
DatagramPacket packet=new DatagramPacket(container,0,container.length);
// 3、阻塞式接收报包receive(DatagramPacket p)
server.receive(packet);
// 4、分析数据 getData() getLength()
byte[] datas=packet.getData();
int len=packet.getLength();
System.out.println(new String(datas,0,len));
// 5、释放资源
server.close();
}
}
步骤1、用DatagramSocket指定端口,创建接收端
步骤2、准备数据,一定转成字节数组
步骤3、封装成DatagramPacket包裹 ,需要指定目的地
步骤4、发送包裹,sent(DatagramPacket p)
步骤5、释放资源
public class UdpClient {
public static void main(String[] args) throws Exception {
System.out.println("发送方启动中...");
// 1、用DatagramSocket制定端口,创建发送端
DatagramSocket client=new DatagramSocket(8888);
// 2、准备数据,一定转成字节数组
String data="珍惜时间!持之以恒";
byte[] datas=data.getBytes();
// 3、封装成DatagramPacket包裹 ,需要指定目的地
DatagramPacket packet=new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",9999));
// 4、发送包裹,sent(DatagramPacket p)
client.send(packet);
// 5、释放资源
client.close();
}
}
服务器与客户端双方实现的步骤,和上述一致。
public class UdpFileServer {
public static void main(String[] args) throws Exception {
System.out.println("接收方启动中...");
// 1、用DatagramSocket制定端口,创建接收端
DatagramSocket server=new DatagramSocket(9999);
// 2、准备容器,封装成DatagramPacket包裹
byte[] container=new byte[1024*60]; //容器最大为60K
DatagramPacket packet=new DatagramPacket(container,0,container.length);
// 3、阻塞式接收报包receive(DatagramPacket p)
server.receive(packet);
// 4、分析数据 getData() getLength()
byte[] datas=packet.getData();
int len=packet.getLength();
//读取的顺序和写出的顺序保持一致
IOUtils.byteArrayTofile(datas, "E:/Java/copy.jpg");
// 5、释放资源
server.close();
}
}
public class UdpFileClient {
static byte[] datas;
public static void main(String[] args) throws Exception {
System.out.println("发送方启动中...");
// 1、用DatagramSocket制定端口,创建发送端
DatagramSocket client=new DatagramSocket(8888);
// 2、准备数据,转成字节数组
byte[] datas = IOUtils.fileToByteArray("C:/Users/ZhouBaiqing/Pictures/Saved Pictures/sun_mountain.jpg");
// 3、封装成DatagramPacket包裹 ,需要指定目的地
DatagramPacket packet=new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",9999));
// 4、发送包裹,sent(DatagramPacket p)
client.send(packet);
// 5、释放资源
client.close();
}
}
---------------------双发可同时发送信息---------------------
public class TalkReceive implements Runnable{
private DatagramSocket server;
private String from;
public TalkReceive(int Port,String from){
this.from = from;
try {
//1、用DatagramSocket制定端口,创建接收端
server=new DatagramSocket(Port);
} catch (SocketException e) {
e.printStackTrace();
}
}
public void run(){
//2、准备容器,封装成DatagramPacket包裹
while(true){
byte[] container=new byte[1024*60]; //容器最大为60K
DatagramPacket packet=new DatagramPacket(container,0,container.length);
//3、阻塞式接收报包receive(DatagramPacket p)
try {
server.receive(packet);
//4、分析数据 getData() getLength()
byte[] datas=packet.getData();
int len=packet.getLength();
String data = new String(datas,0,len);
System.out.println(from+":"+data);
if(data.equals("exit")) break;
} catch (IOException e) {
e.printStackTrace();
}
}
//5、释放资源
server.close();
}
}
public class TalkSend implements Runnable{
private DatagramSocket client;
private BufferedReader reader;
private String toIP;
private int toPort;
public TalkSend(int port,String toIP,int toPort){
this.toIP=toIP;
this.toPort=toPort;
try {
//1、用DatagramSocket制定端口,创建发送端
client = new DatagramSocket(port);
//2、准备数据,一定转成字节数组
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}
public void run(){
//加控制台&字节转字符
while(true){
String data;
try {
data = reader.readLine();
byte[] datas=data.getBytes();
//3、封装成DatagramPacket包裹 ,需要指定目的地
DatagramPacket packet=new DatagramPacket(
datas,0,datas.length,new InetSocketAddress(
this.toIP,this.toPort));
//4、发送包裹,sent(DatagramPacket p)
client.send(packet);
if(data.equals("exit")) break;
} catch (IOException e) {
e.printStackTrace();
}
}
//5、释放资源
client.close();
}
}
---------------------继续加入多线程,实现双向交流,模拟在线聊天---------------------
public class TalkStudent {
public static void main(String[] args) {
//指定自己的发送端口7777,指向对方的接收端口6666
new Thread(new TalkSend(7777,"localhost",6666)).start();
//指定自己的接收端口5555,指定对方的名字为 杜静宜
new Thread(new TalkReceive(5555, "杜静宜")).start();
}
}
public class TalkStudent2 {
public static void main(String[] args) {
//指定自己的接收端口6666,指定对方的名字为 周百青
new Thread(new TalkReceive(6666, "周百青")).start();
//指定自己的发送端口是4444,指向对方的接收端口5555
new Thread(new TalkSend(4444,"localhost",5555)).start();
}
}
1、相比UDP性能略低,UDP倾向于底层数据包的发送和接收
包中写IP地址。
2、用IO流实现数据的传输。http的底层协议是TCP协议,http是超文本传输协议,信息是
明文传输,https是有安全性的ssl加密传输协议。
3、请求响应模式,服务器端监听客户端的请求。建立连接后,使用IO流传输数据。
---------------------单人单向登录---------------------
public class LoginServer {
public static void main(String[] args) throws IOException {
System.out.println("--------Server--------");
//1、指定端口,使用ServerSocket创建服务器
ServerSocket server = new ServerSocket(9999);
//2、阻塞式等待连接 accept
Socket client = server.accept();
System.out.println("一个客户端建立了连接");
//3、操作:输入输出流操作
DataInputStream dis = new DataInputStream(client.getInputStream());
String datas = dis.readUTF();
//分析数据
String[] dataArray = datas.split("&");
for(String info:dataArray){ //遍历数组
String[] userinfo = info.split("=");
if(userinfo[0].equals("userid"))
System.out.println("你的用户名为:"+userinfo[1]);
else if(userinfo[0].equals("passwd"))
System.out.println("你的密码为:"+userinfo[1]);
}
//4、释放资源
dis.close();
client.close();//关闭Socket
//一般服务器不会关闭
//server.close();
}
}
public class LoginClient {
public static void main(String[] args) throws UnknownHostException, IOException{
System.out.println("--------Client--------");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入用户名:");
String userid = br.readLine();
System.out.println("请输入密码:");
String passwd = br.readLine();
//1、建立连接:使用Socket创建客户器+服务器的地址和端口
Socket client = new Socket("localhost",9999);
//2、操作:输入输出流操作
//推荐用Data流,不用去操作字节
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF("userid="+userid+"&"+"passwd"+passwd);
dos.flush();
//3、释放资源
dos.close();
client.close();//关闭客户端
}
}
---------------------多人登录,并完成代码封装---------------------
public class LoginMultiServer {
//声明用户名与密码
static String userid="";
static String passwd="";
public static void main(String[] args) throws IOException {
System.out.println("--------Server--------");
//1、指定端口,使用ServerSocket创建服务器
ServerSocket server = new ServerSocket(9999);
//boolean is=true; //当while(true)循环出错时,可设标志位骗过JVM
//2、阻塞式等待连接 accept
while(true){
Socket client = server.accept();
System.out.println("一个客户端建立了连接");
new Thread(new Channel(client)).start();
}
//一般服务器不会关闭
//server.close();
}
//定义一个静态匿名内部类,方便后续操作
//一个Channel就代表一个客户端,即一个线程,封装了输入输出流
static class Channel implements Runnable{
private Socket client;
private DataOutputStream dos;
private DataInputStream dis;
//编写构造器
public Channel(Socket client) throws IOException{
this.client=client;
try {
//3、操作:输入输出流操作
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
release();
}
}
//接收数据(封装成一个方法)
private String receive(){
String datas="";
try {
datas = dis.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return datas;
}
//发送数据(封装成一个方法)
private void send(String msg){
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//释放资源(封装成一个方法)
private void release(){
try {
if(dos!=null){
//关闭输出流
dos.close();
}
if(dis!=null){
//关闭输入流
dis.close();
}
if(client!=null){
//关闭Socket
client.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//重写run方法(线程体)
//目的:1、验证用户名和密码2、响应3、释放资源
@Override
public void run() {
//分析数据
String[] dataArray = receive().split("&"); //分隔分析
for(String info:dataArray){ //遍历数组
String[] userinfo = info.split("=");
if(userinfo[0].equals("userid")){
System.out.println("你的用户名为:"+userinfo[1]);
userid = userinfo[1];
}
else if(userinfo[0].equals("passwd")){
System.out.println("你的密码为:"+userinfo[1]);
passwd = userinfo[1];
}
}
//判断是否登录成功
if(userid.equals("zbq") && passwd.equals("djy")){//成功
send("登录成功!");
}else{//失败
send("用户名或密码输入错误!");
}
//调用释放资源的方法
release();
}
}
}
public class LoginMultiClient {
//主方法体
public static void main(String[] args) throws UnknownHostException, IOException{
//初始化
String init_msg = new Init().init();
//1、建立连接:使用Socket创建客户器+服务器的地址和端口
Socket client = new Socket("localhost",9999);
//2、发送请求
new Send(client).send(init_msg);
//3、接收响应
new Receive(client).receive();
//4、释放资源
new Release(client).release();
}
//定义一个静态内部类:负责初始化设置
static class Init{
BufferedReader br;
String userid="";
String passwd="";
//定义初始化方法
public String init(){
System.out.println("--------Client--------");
br = new BufferedReader(new InputStreamReader(System.in));
try {
System.out.println("请输入用户名:");
userid = br.readLine();
System.out.println("请输入密码:");
passwd = br.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "";
}
return "userid="+userid+"&"+"passwd="+passwd;
}
}
//定义一个静态内部类:负责发送数据
static class Send{
private DataOutputStream dos;
//构造器中传成员
public Send(Socket client){
try {
//2、操作:输出流操作
//推荐用Data流,不用去操作字节
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//构造一个发送数据的方法
public void send(String msg){
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//定义一个静态内部类:负责接收数据
static class Receive{
private DataInputStream dis;
String result="";
//接收响应
//定义构造器
public Receive(Socket client){
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//写方法
public void receive(){
try {
//反馈结果
result = dis.readUTF();
System.out.println(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//定义一个静态内部类:负责释放资源
static class Release{
private DataOutputStream dos;
private DataInputStream dis;
private Socket client;
public Release(Socket client){
this.client = client;
}
//定义释放资源的方法
public void release(){
try {
if(dos!=null){
//关关闭输出流
dos.close();
}
if(dis!=null){
//关闭输入流
dis.close();
}
if(client!=null){
//关闭客户端
client.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}