Java基础之UDP协议和TCP协议简介及简单案例的实现

Wesley13
• 阅读 700

写在前面的废话:马上要找工作了,做了一年的.net ,到要找工作了发现没几个大公司招聘.net工程师,真是坑爹呀。哎,java就java吧,咱从头开始学呗,啥也不说了,玩命撸吧,我真可怜啊。

摘要:

本片记载刚刚学习的网络编程的内容,网络编程也称 Socket 编程 、套接字编程。

什么是Socket?

用于描述ip地址和端口,是一个通信链的Handle。在Internet上的主机一般运行了多个服务软件,同时提供几种服务,每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。Socket就是为了网络编程提供的一种机制,通信的两端都有socket,网络通信其实就是socket间的通信,数据在两个socket之间通过 IO 传输。(摘自黑马视频ppt).

网络通信的三要素:

IP地址:

网络中设备的标识,也可以用主机名识别,但ip地址唯一,主机名不唯一;

端口号:

用于标识进程的逻辑地址,是不同进程的标识;

传输协议:

也即通信的规则,常见的协议由 UDP 协议 和 TCP协议;

UDP协议和TCP协议

(1)UDP

UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法(百度百科截取)。

百度上讲的有点复杂,不太容易懂,比较通俗的说法就是:UDP协议会把数据打包,然后扔给目标地址,但是这个包能不能扔的到目标机器上,就不管了,udp就只管扔。

所以这种通信协议的优缺点很明显了,优点就是:速度快,效率高;缺点就是:安全性低,容易丢包

(2)TCP

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议(摘自百度百科)。

通俗说法:tcp协议只在已经确定通信双方都能联系上对方的时候才能进行通信:

     使用tcp协议时要先建立连接;

     建立连接的过程:三次握手,如下图,

Java基础之UDP协议和TCP协议简介及简单案例的实现

 UDP协议的简单使用

发送数据流程

  • 创建发送端socket对象;
  • 提供数据,并将数据封装到数据包中;
  • 通过socket服务的发送功能,将数据包发出去;
  • 释放资源;

接收数据流程

  • 创建接收端socket对象;
  • 接收数据;
  • 解析数据;
  • 输出数据;
  • 释放资源;

一个案例:

创建两个控制台程序模拟发送端和接收端,使用udp发送端发送数据,接收端接收数据。

发送端:

SendDemo.java

package com.cherish.Socket;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
 * 使用UDP协议发送数据
 *         创建发送端Socket对象
 *         创建数据并打包
 *         发送数据
 *         释放资源
 * 
 * DatagramSocket:此类表示用来发送和接受数据,基于UDP协议
 * 
 * DatagramSocket():
 * DatagramSocket(int port):
 * */
public class SendDemo {
    public static void main(String[] args) throws IOException {
        //创建发送端Socket对象
        DatagramSocket ds = new DatagramSocket();
        //创建数据并打包  DatagramPacket表示数据包
        //数据 byte[] 设备地址ip 进程的地址 :端口号
        String s = "hello udp,i m coming";
        byte[] bys = s.getBytes();
        int length = bys.length; 
        InetAddress address = InetAddress.getByName("acer-pc");
        int port = 8888;
        DatagramPacket dp = new DatagramPacket(bys, length, address,port);
        //发送数据
        ds.send(dp);
        //释放资源
        ds.close();
        
    }
}

接收端:

ReceiveDemo.java

package com.cherish.Socket;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/*
 * 使用UDP协议接受对象:
 *     创建接收端Socket对象
 *     接受数据
 *  解析数据
 *  输出数据
 *  释放资源
 * */
public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        //创建接收端Socket对象,此处的端口号要跟发送端一致
        DatagramSocket ds = new DatagramSocket(8888);
        //接收数据
        byte[] bys = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bys, bys.length);
        System.out.println("接受前");
        ds.receive(dp);
        System.out.println("接收后");
        //解析数据
        //InetAddress getAddress()
        InetAddress address = dp.getAddress();
        //byte[] getData
        byte[] data = dp.getData();
        int length = dp.getLength();
        //输出数据
        System.out.println("sender ----"+address.getHostAddress());
        System.out.println(new String(data));        
    }

}

 运行结果:
Java基础之UDP协议和TCP协议简介及简单案例的实现

说明:

(1)DatagramSocket类

DatagramSocket() :创建实例,通常用于客户端编程,他并没有特定的监听端口,仅仅使用一个临时的。
DatagramSocket(int port) :创建实例,并固定监听Port端口的报文。
DatagramSocket(int port, InetAddress laddr) :这是个非常有用的构建器,当一台机器拥有多于一个IP地址的时候,由它创建的实例仅仅接收来自LocalAddr的报文。
DatagramSocket(SocketAddress bindaddr) :bindaddr对象中指定了端口和地址。

常用方法:

receive(DatagramPacket p) :接收数据报文到p中。receive方法是阻塞的,如果没有接收到数据报包的话就会阻塞在哪里。
send(DatagramPacket p) :发送报文p到目的地。
setSoTimeout(int timeout) :设置超时时间,单位为毫秒。
close() :关闭DatagramSocket。在应用程序退出的时候,通常会主动的释放资源,关闭Socket,但是由于异常的退出可能造成资源无法回收。所以应该在程序完成的时候,主动使用此方法关闭Socket,或在捕获到异常后关闭Socket。

(2)DatagramPacket类

DatagramPacket类用于处理报文,将字节数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成字节数组。

DatagramPacket(byte[] buf, int length, InetAddress addr, int port) :从buf字节数组中取出offset开始的、length长的数据创建数据对象,目标地址是addr,目标端口是port;
DatagramPacket(byte buf[], int offset, int length, SocketAddress address) :从buf字节数组中取出offset开始的、length长的数据创建数据对象,目标地址是address;

常用方法:

getData() byte[] :从实例中取得报文中的字节数组编码。

**setData(byte[] buf, int offset, int length)**: 设置数据报包中的数据内容

TCP协议的简单使用

tcp客户端发送数据流程:

  • 创建发送端Socket对象(创建连接),Tcp的Socket对象与Udp的有所不同,需注意;
  •  获取输出流对象;
  •  发送数据;
  •  释放资源;

tcp服务端接收数据流程:

  •  创建接收端Socket对象;
  • 监听(阻塞):如果建立连接失败,程序会卡在这里,不往下执行;
  • 获取输入流对象;
  •  获取数据;
  •  输出数据;
  •  释放资源;

案例一:客户端发送数据,服务端接收数据;

ClietDemo.java:

package com.cherish.Socket;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/*
 * 使用tcp协议发送数据
 *         创建发送端Socket对象(创建连接)
 *         获取输出流对象
 *         发送数据
 *         释放资源
 * */
public class TcpClientDemo {
    public static void main(String[] args) throws IOException{
        //创建发送端Socket对象(创建连接)
        Socket s = new Socket(InetAddress.getByName("acer-pc"),8886); 
        //获取输出流对象
        OutputStream os = s.getOutputStream();
        //发送数据
        String str = "hello tcp , i m coming!";
        os.write(str.getBytes());
        //释放资源
        s.close();
    }
}

ServerDemo.java:

package com.cherish.Socket;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * 使用tcp协议接受对象
 *         创建接收端Socket对象
 *         监听(阻塞):如果建立连接失败,程序会卡在这里,不往下执行
 *         获取输入流对象
 *         获取数据
 *         输出数据
 *         释放资源
 * */
public class TcpServerDemo {
    
    public static void main(String[] args) throws IOException {
        //创建接收端Socket对象
        ServerSocket ss = new ServerSocket(8886); 
        //监听
        Socket s = ss.accept();
        //获取输入流对象
        InputStream is = s.getInputStream();
        //获取数据
        byte[] bys = new byte[1024];
        int len; //用于存储读到的字节数
        len = is.read(bys);
        //输出数据
        String client = s.getInetAddress().getHostName();
        System.out.println(client+"发来的数据");
        System.out.println(new String(bys,0,len));
        //释放资源
        s.close();
        //ss.close(); //socket对象一般不释放,因为客户端不止一个,可能有多个客户端会发送数据        
    }    
}

 运行结果:

Java基础之UDP协议和TCP协议简介及简单案例的实现

 案例二:对案例一进行改进,服务端收到数据后,将数据由小写换成大写,然后返回给客户端:

Client.java:

package com.cherish.Socket.TcpDemo_2;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
    public static void main(String[] args) throws IOException {
        //创建发送端socket对象
        Socket s = new Socket(InetAddress.getByName("acer-pc"),8866);
        //获取输出流对象
        OutputStream os = s.getOutputStream();
        //写入数据
        String str = "hello tcp ,ahahahah!!!";
        os.write(str.getBytes());
        System.out.println("数据已发送");
        //获取输入流对象
        InputStream is = s.getInputStream();
        byte[] bys = new byte[1024];
        int len = is.read(bys);
        String backStr = new String(bys,0,len);
        System.out.println(backStr);
        s.close();        
    }
}

Server.java:

package com.cherish.Socket.TcpDemo_2;

import java.io.IOException;
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 IOException {
        //创建服务端接收对象
        ServerSocket ss = new ServerSocket(8866);
        //监听 来自客户端的连接
        Socket s = ss.accept();
        //获取输入流对象
        InputStream is = s.getInputStream();
        //获取数据
        byte[] bys = new byte[1024];
        int len = is.read(bys);
        String str = new String(bys,0,len);
        //输出数据
        System.out.println(str);
        //转换数据
        String upperStr = str.toUpperCase();
        //获取输出流对象
        OutputStream os = s.getOutputStream();
        //写入数据到流中
        os.write(upperStr.getBytes());
        //释放资源
        s.close();
    }
}

运行结果:

Java基础之UDP协议和TCP协议简介及简单案例的实现

Java基础之UDP协议和TCP协议简介及简单案例的实现

案例三:用tcp模拟一个登录功能,tcp客户端输入用户名和密码,然后发送给服务端,服务端根据输入结果返回登录或失败给客户端;

LoginClient.java:

package com.cherish.Socket.LoginCase;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

/*
 * 模拟用户登录案例
 * */
public class LoginClient {
    public static void main(String[] args) throws IOException {
        //创建客户端socket对象
        Socket s = new Socket("acer-pc",8885);
        //获取用户名和密码
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入用户名");
        String userName = br.readLine();
        System.out.println("请输入密码");
        String password = br.readLine();        
        //获取输出流对象
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);
        //写出数据
        out.println(userName);
        out.println(password);
        //获取输入流对象
        BufferedReader serverBr = new BufferedReader(new InputStreamReader(s.getInputStream()));
        //获取服务端返回的数据
        String backStr = serverBr.readLine();
        System.out.println(backStr);
        //关闭资源    
        s.close();
    }
}

LoginServer.java:

package com.cherish.Socket.LoginCase;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class LoginServer {
    public static void main(String[] args) throws IOException {
        //创建服务端socket对象
        ServerSocket ss = new ServerSocket(8885);
        //监听
        Socket s = ss.accept();
        //获取输入流对象
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        //获取用户名和密码
        String userName = br.readLine();
        String password = br.readLine();
        //判断用户名和密码是否正确
        boolean flag = false;
        if (userName.equals("cherish")&&password.equals("123")) {
            flag = true;
        }
        //获取输出流对象
        PrintWriter out = new PrintWriter(s.getOutputStream(),true);
        //返回判断信息
        if (flag) {
            System.out.println("成功");
            out.println("登录成功");
        }else {
            out.println("登陆失败");
        }
        //释放资源
        s.close();
        //ss.close();//服务端一般不关闭                
    }
}

运行结果:

Java基础之UDP协议和TCP协议简介及简单案例的实现

Java基础之UDP协议和TCP协议简介及简单案例的实现

 结语:本篇博客根据传智播客基础视频整理,记载比较简单,但大致能演示清楚udp和tcp的区别及其用法。个人学习java才不到4天时间,对于java的一些知识点不能讲解的很清楚,因此代码注释写的不是很详细,见谅见谅!哈哈!

本片博客的代码我上传到百度云盘,需要的可自取:

链接:https://pan.baidu.com/s/1-dTfG9GY5MBIAlNJg1v0mw 
提取码:3dw6 
复制这段内容后打开百度网盘手机App,操作更方便哦

本文同步分享在 博客“CherishTheYouth”(CNBlog)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这