网络编程 套接字

发送端和接收端

在一次网络数据传输时:

发送端:数据的发送方进程,称为发送端 。发送端主机即网络通信中的源主机。

接收端:数据的接收方进程,称为接收端 。接收端主机即网络通信中的目的主机。

收发端:发送端和接收端两端,也简称为收发端

客户端和服务端

服务端:在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端 ,可以提供对外服务。

客户端:获取服务的一方进程,称为客户端

最常见的场景,客户端是指给用户使用的程序,服务端是提供用户服务的程序:

  1. 客户端先发送请求到服务端

  2. 服务端根据请求数据,执行相应的业务处理

  3. 服务端返回响应:发送业务处理结果

  4. 客户端根据响应数据,展示处理结果(展示获取的资源,或提示保存资源的处理结果)

Socket套接字

Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。

基于Socket套接字的网络程序开发就是网络编程。

我们学习网络编程,和应用层打交道就是家常便饭,因为我们的编写程序都要在这里完成,使用操作系统提供的一组api(socket api,传输成提供给应用层)。

传输层为我们提供了两套协议:TCP与UDP。

TCP:有连接、可靠传输、面向字节流、全双工。

UDP:无连接、不可靠传输、面向数据流、全双工。

有/无连接:

这个概念会有些抽象,在逻辑上的链接,不是通过物理通过数据线、网线等方式,而是彼此之间保存对方的信息。就如同身份证一般,身份证上有着你的个人信息,是属于你的物品,即使弄丢了他还是属于你,而不是身份证长在你身上才是你的,离开了就不是了。

在TCP协议中,有连接就是在两个端口里互相保存着对方的信息,能够建立链接,这就是有连接

而DUP协议没有这个功能,不会和对方建立连接,保存对方的信息,这便是无连接

可靠/不可靠传输

网络传输中会出现数据丢失的情况:光电信号由于某些原因遭到破坏、干扰而丢失信息或者变成无效信号,被识别出来数据错误后将其丢弃,简称丢包 。

可靠传输:尽可能提高数据传输的成功率,减少丢包的现象出现。出现丢包现象会及时补发,确保信息能够全部发送过去。缺点:消耗的开销会很大。

不可靠传输:不会管接收方收没收到,只管把数据发送出去就完事了。

将路由器/交换机转发的数据看出跑动的汽车,路由器/交换机看成一个一个的十字路口,当路由器/交换机需转发的数据量超过数据转发数据量的上限,就会出现堵车的现象,进而造成丢包现象出现。

最直接的表现就是在公共场所连接公共网络会很卡。

面向字节流/数据流

顾名思义,读写的时候是以字节为单位还是以一个数据报为单位(不是字符)。

全双工/半双工

**全双工:**一个通信链路支持双向通信(能读能写)

**半双工:**一个通信链路支持单向通信(只能读或者写)

举例子:单行路就是半双工,对面的车就得让行等待。双行道就是全双工,来往都行,不受影响。

UDP的socket api

DatagramSocket类

把操作网卡转换成操作socket文件,间接操控网卡,用于发送和接收UDP数据。

构造DatagramSocket端口号

DatagramSocket():创建一个UDP的数据报套接字的Socket,,绑定到本机的任意一个随机端口。(客户端不需要指定端口号,用系统随机分配一个。)

DatagramSocket(int port):创建一个UDP的数据报套接字的Socket,绑定到本机的指定端口(一般用于服务端,区分同一个主机上不同的应用程序)

接收与发送方法

void recieive(DatagramPacket p):从此套接字接收数据报,若没接收到数据报则阻塞等待

void send(DatagramPacket p):从此套接子发送数据包,不会阻塞,直接发送

void close():关闭此数据报套接字

DatagramPacket

构造方法

DatagramPacket(byte [] buf , int length):构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)

DatagramPacke(byte [] , int offset ,int length,SocketAddress address):构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

接收方法

getAddress():从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址

getPort():从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
getData():获取数据报中的数据

getBytes():转换字符串为字节

代码实现

回显服务器

java 复制代码
public class UdpEchoServer{
    private DatagramSocket socket = null;

    public UdpEchoServer(int port) throws SocketException {//网络异常处理
//        指定一个固定端口号,给服务器使用
        socket = new DatagramSocket(port);
    }
//服务器启动
    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true){
            //1.接收读取请求信息
//            DatagramPacket表示一个UDP数据报,传入字节数组就是保存接收UDP的载荷部分。
//            DatagramPacket中也能保存了其他五元组的信息
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);//创建空对象
            socket.receive(requestPacket);//接收客户端发来的数据
//          读取到的二进制转化成字符串
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
//                                                  拿到字节数组,指定有效范围起始位置,有效的长度
            //在调用receive之前,先构一个造新的对象,把对象传递给receive,receive就会把数据从网卡里读出来,填充到参数中


            //2.根据请求计算响应(重点功能)但因为是回显服务器,这一步被简化,你发出上面回应什么
            String response = process(request);

            //3.把响应环境返回给客户端                               得到的字节      不能使用response.length(),代表String字符个数
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,//字节个数
                    requestPacket.getSocketAddress());//返回IP和端口号
            //发送UDP,但因为没有存储对方信息,需要我们手动指定目的IP和目的端口
            //requestPacket中存储了客户端的源IP和源端口,可以将其作为目的IP和目的端口

            socket.send(responsePacket);
            //4。打印日志
            System.out.printf("[%s:%d] req: %s, res :%\n",
                    requestPacket.getAddress().toString(),
                    requestPacket.getPort(),
                    request,
                    response);
        }
    }

    private String process(String request) {
        return request;
    }
 public static void main(String[] args) throws IOException {
        UdpEchoServer server = new UdpEchoServer(9090);
        server.start();
    }
}

socket对象代表网卡文件,对socket读文件相当于接收网卡中的数据,写文件相当于网卡发送数据

复制代码
public class UdpEchoClient {
    private DatagramSocket socket = null;

    public UdpEchoClient(int port) throws SocketException {

        socket = new DatagramSocket(port);
    }

getSocketAddress方法以读取接受存储到DatagramPacket里的源IP和源端口,特别的,hetAddress只能拿到IP,getPort只能拿到端口

DatagramPacket虽然说是读取UDP报头信息,但实际上他也会读取IP报头里 的信息,获取源IP和目的IP。

在while循环中:

构建DatagramPacket对象requestPacket (创建一个DUP数据包,报头+载荷),由receive接收请求数据包(作为输出型参数接收)往里面填充

DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);

socket.receive(requestPacket);//客户端若没有发来数据会阻塞等待

将UDP数据包中载荷取出:requestPacket.getData()可以拿到字节数组,requestPacket.getLength()可以拿到长度,然后构建一个Sting。

由于这里是回显服务器,你传进来是什么发回去就是什么,将Sting进行包装。

复制代码
String request = new String(requestPacket.getData(),0,requestPacket.getLength());

String response = process(request);

response.getBytes()将字符串转换为字节数组、response.getBytes().length得到字节长度,requestPacket.getSocketAddress()取出源IP和源端口信息,然后新构建一个DatagramPacket数据包,然后调用send发送回去。

复制代码
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
复制代码
socket.send(responsePacket);

用户端

java 复制代码
public class UdpEchoClient {

    private String serverIP;

    private int serverPort;

    private DatagramSocket socket = null;
          //指定访问服务器的地址
    public UdpEchoClient(String serverIP,int serverPort) throws SocketException {
        this.serverIP = serverIP;//目的IP
        this.serverPort = serverPort;//目的端口
        //serverIP是目的IP,serverPort是目的端口,源IP是客户端主机IP,源端口是本机一个系统随机分配的端口
        socket = new DatagramSocket();//不能传固定源端口,每次都是随机分配使用,一个固定的端口可能会被其他应用使用导致无法使用。

    }
    public void start() throws IOException {

        while(true) {
            System.out.println("输入发送的信息");
            Scanner scanner = new  Scanner(System.in);

            if (!scanner.hasNext()) {
                break;
            }
            String request = scanner.next();
            //构造DatagramPacket数据报,传入载荷、目的IP和目的端口,InetAddress.getByName()方法按照字符串创建(给人看的)的IP转换成字符串(给机器看的)。
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                    InetAddress.getByName(serverIP), serverPort);
            //发送数据报
            socket.send(requestPacket);
            //接收服务器响应,创建一个数据报,用具接收服务端的信息
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePacket);
            //解析,将收到的数据报转化成字符串类型
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
        client.start();
    }
}

用户端的代码这里就不展开讲了,基本上和服务端一样的。

相关推荐
Hello.Reader1 小时前
ngx_http_limit_conn_module精准连接控制
网络·网络协议·http
qq_386322692 小时前
华为网路设备学习-21 IGP路由专题-路由过滤(filter-policy)
前端·网络·学习
firshman_start9 小时前
第十五章,SSL VPN
网络
Johnstons9 小时前
AnaTraf:深度解析网络性能分析(NPM)
前端·网络·安全·web安全·npm·网络流量监控·网络流量分析
落——枫9 小时前
路由交换实验
网络
Johny_Zhao9 小时前
K8S+nginx+MYSQL+TOMCAT高可用架构企业自建网站
linux·网络·mysql·nginx·网络安全·信息安全·tomcat·云计算·shell·yum源·系统运维·itsm
小诸葛的博客10 小时前
华为ensp实现跨vlan通信
网络·华为·智能路由器
稳联技术10 小时前
Ethercat转Profinet网关如何用“协议翻译术“打通自动化产线任督二脉
linux·服务器·网络
摸鱼仙人~11 小时前
HTTP 响应状态码总结
网络·网络协议·http
liyi_hz200811 小时前
O2OA(翱途)开发平台系统安全-用户登录IP限制
运维·服务器·网络·o2oa开发