网络编程相关知识

这篇具有很好参考价值的文章主要介绍了网络编程相关知识。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写一个应用程序,让这个程序可以使用网络通信,这里就需要调用传输层提供的api,传输层提供协议,主要是两个:
UDP,TCP,它们分别提供了一套不同的api,socket api.

UDP和TCP

UDP:无连接,不可靠传输,面向数据报,全双工
TCP:有连接,可靠传输,面向字节流,全双工
一个客户端可以连接多个服务器,一个服务器也可以连接多个客户端(多对多)

连接(connection)

链接(link)快捷方式
windows上只有软链接(符号链接),通过一个文件,文件的内容保存另一个文件的路径,实现软链接
Linux除了支持软连接,还支持硬链接(两个路径,共享同一个inode节点)

可靠传输和不可靠传输

可靠传输,不是说,A给B发信息100%能收到,而是A尽可能的把消息传给B,并且在传输失败或者成功的时候,A能够感知得到
这里的可靠与否,不能说明谁好谁坏,可靠传输想要实现,也是需要一定的成本,所以,有舍才有的,我们应该将这两种属性视为各自的特性
TCP和文件操作类似,都是"流"式的(由于这里传输的单位是字节,称为字节流)
比如:
通过TCP读写100字节的数据
可以一次读100字节
一次读写50字节,分两次
一次读写10字节,分10次
UDP是面向数据报,读写的基本单位,是一个UDP数据报(包含了一系列是数/属性)
全双工:一个通道,可以双向通信
半双工:一个通道,只能单向通信
UDP更简单,先认识UDP的socket api
两个核心的类:
1.DatagramSocket
操作系统,使用文件这样的概念,来管理一些硬件资源,网卡,操作系统也是使用文件的方式来管理网卡的,
表示网卡这样的文件,称为socket文件
Java中的socket对象,对应着系统里的socket文件(最终还是要落到网卡上)
要进行网络通信,必须得先有socket对象
网络编程相关知识,网络,单片机,stm32
一个客户端的主机,上面运行的程序有很多,可能存在手动指定的端口号被别的程序占用的了,让系统分配,更为合适
网络编程相关知识,网络,单片机,stm32

2.DatagramPacket
表示UDP数据报,代表了系统中设定的UDP数据报的二进制数据

方法签名 方法说明
DatagramPacket(byte[]buf, int length) 构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[]buf, int offset, int length,SocketAddress address) 构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

网络编程相关知识,网络,单片机,stm32
接下来,开始手动编写一个UDP客户端服务器

回显服务器

UDP版本

服务器

package network;

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

public class UdpEchoSerevr {
    DatagramSocket socket = null;
    public UdpEchoSerevr(int port) throws SocketException {
        //这里抛出的异常,最常见的情况是端口号被占用
        socket = new DatagramSocket(port);
    }
    //使用下面的start取调用服务器
    public void start() throws IOException {
        System.out.println("服务器启动!");
        //反复的,长期的执行针对客户端请求处理的逻辑.
        while(true){
            DatagramPacket packet = new DatagramPacket(new byte[4096],4096);
            //一个服务器,在执行过程中,主要执行的是三个核心任务
            //1.读取请求,并解析
            //下面这个方法中的参数DatagramPacket是一个"输出型参数"
            //传入receive的是一个空的对象
            //receive内部就会把这个空的对象的内容给填充上,
            //当receive执行结束的时候,就会得到一个装满内容的DatagramPacket
            socket.receive(packet);
            //要将数据报转换为字符串的前提是,客户端发的数据就是一个文本的字符串
            String request = new String(packet.getData(),0,packet.getLength());
            //2.根据请求,计算响应
            String response = process(request);
            //3.把响应写回给客户端
            //此时要告知网卡,要发送给客户端的内容是什么,要发给谁
            //getSocketAddress可以得到客户端主机的ip和端口号
            DatagramPacket responseRequest = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    packet.getSocketAddress());
            socket.send(responseRequest);
            System.out.printf("[%s:%d] req: %s,resp: %s\n",packet.getAddress().toString(),packet.getPort(),request,response);
        }
    }
    public String process(String request){
        return request;
    }
    public static void main(String[] args) throws IOException {
        UdpEchoSerevr serevr = new UdpEchoSerevr(9090);
        serevr.start();
    }
}

客户端

package network;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    DatagramSocket socket = null;
    private String serevrIP;
    private int serverPort;
    public UdpEchoClient(String IP,int Port) throws SocketException {
        serevrIP = IP;
        serverPort = Port;
        socket = new DatagramSocket();
    }
    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("客户端启动!");
        while(true){
            System.out.println("->");
            String request = scanner.next();
            //构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。
            //构造请求对象,并发给服务器
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serevrIP),serverPort);
            socket.send(requestPacket);
            //读取服务器的响应,并解析出响应内容
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            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("192.168.38.196" ,9090);
        client.start();
    }
}

字典服务器

package network;

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;

public class UdpditServer extends UdpEchoSerevr{
    public static HashMap<String,String> hashMap = new HashMap<>();
    public UdpditServer(int port) throws SocketException {
        super(port);
        hashMap.put("cat","猫");
        hashMap.put("dog","狗");
        hashMap.put("girl","女孩");
        hashMap.put("boy","男孩");
    }

    @Override
    public String process(String request) {
        return hashMap.getOrDefault(request,"没有查到相关信息");
    }

    public static void main(String[] args) throws IOException {
        UdpditServer udpditServer = new UdpditServer(9090);
        udpditServer.start();
    }
}

TCP版本

分量要比UDP更重,用到更多的协议
TCP提供的API主要也是有两个类:
ServerSocket(给服务器使用的socket)
Socket(既会给服务器使用,也会给客户端使用)
这里不需要专门的类来表示TCP数据报,因为TCP是进行字节流传输的,是一个字节一个字节的进行传输的,而一个TCP数据报,就是一个字节数组

服务器

package network;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    //创建线程池,方便多线程实现多个客户端同时访问服务器
    private ExecutorService service = Executors.newCachedThreadPool();
    private ServerSocket serverSocket = null;
    public TcpEchoServer(int port) throws IOException {
        serverSocket =new ServerSocket(port);
    }
    public void start() throws IOException {
        //进入start方法后,第一件事不是读取客户端的请求,而是处理客户端的"连接"
        //内核中的"连接",就像一个一个"代办事项",这些代办事项在一个队列 的数据结构中,
        //应用程序就要一个一个的完成这些任务,要完成任务,就要先取出这些任务
        //取出任务,需要用到下面这个方法
        //当客户端和服务器进行数据交互的时候,就会进行"握手"
        //"握手"成功后,就会生成一个这样的代办事项,称为"连接"
        //客户端的应用程序在生成serversocket文件的时候,socket内部会有一个队列,用来管理上述的"连接"
        //每个socket都有这样一个队列,各自独立
        //当没有客户端的时候,就会进入阻塞
        Socket clientSocket = serverSocket.accept();
        //accept是把内核中已经建立好的连接,从serverSocket的队列中给拿到应用程序中,但是这里的返回值并非是一个"connection"对象
        //而是一个socket对象,通过这个socket对象和对方进行网络通信
        service.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
    //通过这个方法,来处理连接的逻辑
    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d]客户端上线!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        //接下来,就可以进行读取请求,根据请求计算响应,返回响应
        //socket内部包含两个字节流对象,可以把这两个字节流获取到,完成后续的工作
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()){
            //一次连接中,可能会涉及到多次请求/响应
            while (true){
                //1.读取请求并解析,为了方便读取,直接使用Scanner
                Scanner scanner = new Scanner(inputStream);
                if (!scanner.hasNext()){
                    //读取完毕,客户端下线
                    System.out.printf("[%s:%d]客户端下线!",clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                //这个代码暗含一个规定,客户端发过来的数据,必须是一个文本数据,同时,还得带有空白符作为分割(比如换行)
                String request = scanner.next();//next就是读取数据,一直读到空白符结束
                //2.根据请求计算响应
                String response = process(request);
                //3.把响应写回给客户端,把outputStream使用PrinterWriter包裹一下,方便进行发数据
                PrintWriter writer = new PrintWriter(outputStream);
                //此处使用PrintWriter的println方法,把响应返回给客户端
                //次数用println就是为了在结尾加上一个\n,为方便客户端读取响应,使用Scanner.next读取
                writer.println(response);
                //这里还需要加一个"刷新缓冲区"的操作
                //IO操作是比较消耗资源的,相比于访问内存,进行IO次数越多,程序的速度就越慢,
                //使用一块内存作为缓冲区,写数据的时候,先写道缓冲区内进行一波缓冲,统一进行IO
                //PrintWriter内置了缓冲区,手动刷新,确保这里的数据是真的通过网卡发出去了,而不是残留在内存缓冲区中
                writer.flush();//不加这一句也不一定错,缓冲区满了的时候,也会触发刷新,程序退出也会
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            //每次读取一个连接,都会创建一个socket,会很占用内存,因此,需要确保及时被close
            clientSocket.close();
        }
    }
    public String process(String request){
        return request;
    }
    public static void main(String[] args) throws IOException {
        TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);
        tcpEchoServer.start();
    }
}

客户端

package network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
    private Socket socket = null;
    //要和服务器通信,就需要知道,服务器所在的位置
    public TcpEchoClient(String ServerIp,int ServerPort) throws IOException {
        //这个new操作之后,就完成了TCP的连接
        socket = new Socket(ServerIp,ServerPort);
    }
    public void start(){
        System.out.println("客户端启动!");
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()){
            while (true){
                //1.从控制台输入字符串
                System.out.println("->");
                Scanner scanner = new Scanner(System.in);
                String request = scanner.next();
                //2.把请求发送给服务器
                PrintWriter writer = new PrintWriter(outputStream);
                writer.println(request);
                writer.flush();
                //3.读取服务器的响应,并打印
                Scanner scanner1 = new Scanner(inputStream);
                String response = scanner1.next();
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

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

解决高并发问题:
1.开源:引入更多的硬件资源.
2.节流:提供单位硬件资源能够处理的请求数(IO多路复用)文章来源地址https://www.toymoban.com/news/detail-699010.html

到了这里,关于网络编程相关知识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Day 1. 51单片机的学习和相关概念

    驱动 裸机驱动:51——s3c2440——linux Linux驱动 寄存器:全局变量 :按位与 :指定位置0 | :按位或 :指定位置1 ^ :按位异或 : 指定位翻转 MCU:是一种集成了处理器、存储器、输入/输出接口和其他外设的单芯片计算机系统。MCU通常用于嵌入式系统中,如智能家居、智能手表

    2024年04月13日
    浏览(14)
  • STM32单片机4*4矩阵键盘相关代码

    STM32单片机4*4矩阵键盘相关代码

           矩阵键盘是我们学习32单片机中十分常见的模块。对于我们掌握32单片机的基本要求有很大的帮助。其核心原理是利用键盘按键按下时产生的电位变化来判断是否按下以及利用行列电平变化来得到按键在矩阵键盘位置的思路。本文简述其使用的相关代码。         

    2024年02月07日
    浏览(14)
  • c51单片机(预备知识)

    c51单片机(预备知识)

            单片机又称单片微控制器,它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上。相当于一个微型的计算机,和计算机相比,单片机只缺少了I/O设备(小键盘、LED显示器)。 0)  无源晶振:12MHZ 1) 振荡周期 :也称时钟周期,是指为单片机提供

    2024年02月08日
    浏览(82)
  • 聊聊单片机编程测量电机的电流

    聊聊单片机编程测量电机的电流

      要测量电机的电流,可以使用电流传感器来实现。常见的电流传感器有霍尔效应传感器和电阻式传感器。 在单片机编程中,可以通过 ADC(模拟数字转换器)模块来实现对电流传感器输出电压的采样和转换。下面是一个简单的步骤: 连接电流传感器:将电流传感器的输出引

    2024年02月15日
    浏览(8)
  • 单片机----汇编语言入门知识点

    单片机----汇编语言入门知识点

    目录 汇编语句的格式 汇编语句的两个基本语句 子程序的调用 查表程序设计 1.x和y均为单字节数的查表程序设计 2.x为单字节数y为双字节数的查表程序设计 3.x和y均为双字节数的查表程序设计 分支转移程序设计 1.单分支选择结构 2.多分支选择结构 循环程序设计 (1) 计数循环控

    2024年04月28日
    浏览(11)
  • 51单片机定时器基础知识

    经验总结:定时器0工作方式1的溢出中断初始值计算 1.晶振11.0592M 11.0592MHz除12为921600Hz,就是一秒921600次机器周期,50ms=46080次机器周期。 65536-46080=19456(4c00) TH0=0x4c,TL0=0x00 2.晶振12M 12MHz除12为1MHz,也就是说一秒=1000000次机器周期。50ms=50000次 机器周期。 65536-50000=15536(3cb0) TH0=0x

    2024年02月04日
    浏览(20)
  • 单片机编程-CAN通讯-理解与实现

    单片机编程-CAN通讯-理解与实现

    日期 作者 版本 说明 2023.02.03 Mr.Zheng V1.1 CAN通讯个人笔记,初版 最近刚刚做完一个较复杂项目,为强化巩固,准备写几篇笔记方便后续回溯,本篇重点是个人对CAN通讯的理解与实现,第一部分为CAN的模型架构,CAN的功能实现是第二部分,需要一定的编程基础,希望能够给初学

    2024年02月16日
    浏览(14)
  • 单片机中的 _nop_() 延时以及其相关的基础扩展

    单片机中的 _nop_() 延时以及其相关的基础扩展

    最近还是继续做着项目,因为在某 8051 内核芯片上使用到了 I2C 通讯,又需要 _nop_() 函数来实现 us 延时,那么正好来写一篇由 _nop_() 函数引起的一系列基本概念 。 本文的内容包括:对 nop 的认识,单片机中的 nop 函数做延时的一些注意事项,以及单片机中基本的指令周期,机

    2024年02月05日
    浏览(12)
  • 51单片机编程应用(C语言):串口通信

    51单片机编程应用(C语言):串口通信

    目录 通信的基本概念和种类    1.1串行通信与并行通信 ​编辑 1.2同步通信与异步通信 1.3单工,半双工,全双工   1.4通信速率  二、波特率和比特率的关系 串口通信简介: 1.接口标准 RS-232 2、D型9针接口定义 3.通信协议: 2.串口内部结构  51单片机串口相关寄存器   1.80c

    2024年02月19日
    浏览(46)
  • 蓝桥杯单片机知识点整合——临时抱佛脚

    蓝桥杯单片机知识点整合——临时抱佛脚

    目录 复习使用,代码根据网上资料修改,仅供参考 ds1302 原理图  手册 ds1302.c main.c onewire 原理图 手册 onewire.c main.c IIC PCF8591 原理图 手册 iic.c main.c AT2402 原理图 手册 main.c 串口UART uart.c main.c 发送数据 中断接收数据 超声波 ult.c main.c N555频率输出 main.c PWM控制LED ———————

    2023年04月24日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包