udp/tcp回显网络编程

news2024/11/15 13:53:44
udp
DatagramSocket 

用于接收和发送udp数据报


构造方法:

  • DatagramSocket():创建一个UDP数据报套接字的Socket,绑定到本地上 一个随机可用端口上,一般用于客户端
  • DatagramSocket(int port):创建一个UDP数据报套接字的Socket,绑定到指定端口上,一般适用于服务器端

DatagramSocket方法:

  • void receive(DatagramPacket p):接收套接字数据报p,如果此时还没有发送,便会阻塞
  • void send(DatagramPacket p):发送套接字数据报p,不会阻塞,直接发送
  • void close():关闭此数据报套接字
DatagramPacket:

udp发送和接收的数据报形式


构造方法:

  • DatagramPacket(byte[] buf,int length):构造一个DatagramPacket对象来接收发送来到数据报,将数据内容放在第一个字节数组中,第二个参数是指定接收内容的长度。(用于接收时)
  • DatagramPacket(byte[] buf,int offset,int length,SocketAddress address):接收发来的数据报,并将内容放进buf数组中,选中需要截取内容的索引[offset,length)。address:指定目的主机的ip和端口号。(用于发送时)

DatagramPacket方法:

  • getSocketAddress():获取发送端的ip地址。
  • getPort():获取发送端的端口
  • byte[] getData():获取数据报中的内容

udp回显服务器实现:
服务器端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;

public class udpServer {
    //服务器端
    private DatagramSocket socket = null;

    public udpServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

    public void start() throws IOException {
        //System.out.println(socket.getPort());
        //returns the port to which the socket is connected  未连接套接字时 返回-1
        //如果想得到服务器端的端口 要使用socket.getLocalPort()
        System.out.println("服务器启动");
        //构建一个DatagramPacket来接收客户端发来的消息
        while(true){
            //创建一个DatagramPacket填充对象,用来接收从客户端发送来的数据报
            DatagramPacket reqPacket = new DatagramPacket(new byte[4096],4096);

            //如果没有数据报发送,receive发送会阻塞等待
            socket.receive(reqPacket);

            //转换成我们看得懂的字符串形式 ----- 客户端发送来的请求
            String request = new String(reqPacket.getData(),0,reqPacket.getLength());

            //服务器端做出响应
            String res = RESPONSE(request);

            //构建一个DatagramPacket将响应后的结果发送回客户端
            //注意需要有客户端socketAddress
            DatagramPacket respPacket = new DatagramPacket(res.getBytes(StandardCharsets.UTF_8),0,res.getBytes().length,
                    reqPacket.getSocketAddress());

            //发送数据报
            socket.send(respPacket);
            System.out.println("服务器端口:"+socket.getLocalPort()+": 客户端[ip:"+respPacket.getAddress()+" 端口:"+reqPacket.getPort()
                                +"] req:"+request+" res:"+res);
        }
    }
    public String RESPONSE(String req){
        return req;
    }

    public static void main(String[] args) throws IOException {
        udpServer server = new udpServer(8080);
        server.start();
    }
}

值得注意的是:DatagramSocket的getPort/getAddress方法,返回的都是连接方的端口和ip,并不是本地的。而DatagreamPacket的getPort/getAddress方法,返回的都是本地的端口和ip地址。如果你还没有连接成功时,打印socket.getPort(),虽然这时候你已经给出了指定端口,但这个方法的返回值是连接端的,还没连接时返回-1


客户端
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class udpClient {
    //目的端ip
    private String severIp;
    //目的端端口
    private int severPort;
    private DatagramSocket socket;

    public udpClient(String severIp,int severPort) throws SocketException {
        socket = new DatagramSocket();
        this.severIp = severIp;
        this.severPort = severPort;
    }

    public void start() throws IOException {
        Scanner sc = new Scanner(System.in);
        System.out.println("客户端启动");
        while(true){
            System.out.print(">>");
            String request = sc.nextLine();
            if(request.equals("exit")){
                System.out.println("退出");
                socket.close();
                return;
            }
            //给出消息发出的目的端ip和端口 (服务器ip端口)
            DatagramPacket reqPacket = new DatagramPacket(request.getBytes(StandardCharsets.UTF_8),request.getBytes().length
            ,InetAddress.getByName(severIp),severPort);

            //发送
            socket.send(reqPacket);

            //接收响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);

            //转换成字符串形式
            String res = new String(responsePacket.getData(),0, responsePacket.getLength());
            //打印响应
            System.out.println(res);
        }
    }

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

注意:当传服务器端的ip地址时,此时我们这里给的是一个字符串,但参数接收的是一个32位整数形式,所以我们需使用InetAddress.getName(String hostage)做一下转换


tcp
SeverSocket 

服务器端Socket API


构造方法:

  • SeverSccket(int port):创建一个服务器端流套接字Socket,并绑定到指定端口

SeverSocket的方法:

  • Socket accept():监听指定端口(创建时绑定的端口),如果有客户端连接后,返回一个服务端Socket对象,否则阻塞等待
  • void close():关闭套接字
Socket

客户端Socket,或服务器端的accept方法收到有客户端连接后返回的服务端Socket

无论是客户端还是服务器端,都是连接建立后,保存对端的信息


构造方法:

Socket(String severIp,int severPort):创建一个客户端Socket,与对应的主机端口建立连接


Socket的方法:

  • InetAddress():返回套接字所连接的地址
  • InputStream getInputStream():
  • OutputStream getOutStream():

ps:tcp是面向字节流传输的


tcp回显服务器实现

服务器端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class tcpSever {
    private ServerSocket socket;

    public tcpSever(int port) throws IOException {
        socket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动");
        //与服务器建立连接 返回一个服务器端Socket
        Socket clickClient = socket.accept();

        processConnection(clickClient);
    }
    public void processConnection(Socket clientSocket){
        System.out.println("客户端上线[ip:"+clientSocket.getInetAddress().toString()+"  port:"+clientSocket.getPort()+"]");
        try(InputStream inputStream = clientSocket.getInputStream(); OutputStream outputStream = clientSocket.getOutputStream()) {
            while(true){
                //读取结果
                //输入流 会等待客户端输入东西 阻塞在这里 (通过Scanner的方法都会造成阻塞)
                Scanner sc = new Scanner(inputStream);
                if(!sc.hasNext()){
                    //没有数据了 断开连接
                    System.out.println("客户端下线[ip:"+clientSocket.getInetAddress()+"  port:"+clientSocket.getPort());
                    socket.close();
                    break;
                }
                //遇到换行/空白结束
                String req = sc.next();

                //服务器响应
                String resp = process(req);

                //OutputStream没有写String的方法
                //1.将其转换成字节数组
                //2.使用PrintWriter-----打印流-----字符打印流/字节打印流
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(resp);
                printWriter.flush();
                System.out.println("客户端:[req:"+req+" resp:"+resp+" ip:"+clientSocket.getInetAddress()+" port:"+clientSocket.getPort()+"]");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public String process(String req){
        return req;
    }

    public static void main(String[] args) throws IOException {
        tcpSever sever = new tcpSever(8080);
        sever.start();
    }
}

客户端
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class udpClient {
    //目的端ip
    private String severIp;
    //目的端端口
    private int severPort;
    private DatagramSocket socket;

    public udpClient(String severIp,int severPort) throws SocketException {
        socket = new DatagramSocket();
        this.severIp = severIp;
        this.severPort = severPort;
    }

    public void start() throws IOException {
        Scanner sc = new Scanner(System.in);
        System.out.println("客户端启动");
        while(true){
            System.out.print(">>");
            String request = sc.nextLine();
            if(request.equals("exit")){
                System.out.println("退出");
                socket.close();
                return;
            }
            //给出消息发出的目的端ip和端口 (服务器ip端口)
            DatagramPacket reqPacket = new DatagramPacket(request.getBytes(StandardCharsets.UTF_8),request.getBytes().length
            ,InetAddress.getByName(severIp),severPort);

            //发送
            socket.send(reqPacket);

            //接收响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);

            //转换成字符串形式
            String res = new String(responsePacket.getData(),0, responsePacket.getLength());
            //打印响应
            System.out.println(res);
        }
    }

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

注意:

  1. 在tcp的Socket中,ip地址可以直接传字符串类型的,不需要像udpSocket那样转成32位整数形式
  2. 我们读通过next()读,写通过println写。这是设计好了的。使换行符变成我们的消息隔断符,使我们知道每一段消息的头和尾,解决粘包问题
  3. 在运行tcp回显服务器时,必须先开服务器端,再开客户端因为如果先开客户端的话,此时没有服务器与之相连,会抛异常------对应的即为tcp的是有连接的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1643674.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python项目】基于opencv的的【疲劳检测系统】

技术简介:使用Python技术、OpenCV图像处理库、MYSQL数据库等实现。 系统简介:用户可以通过登录系统平台实现实时的人脸照片的拍摄和上传,结合上传图像的内容进行后台的图像预处理和运算分析,用户可以通过照片分析界面查看到当前检…

Unity UGUI Image 点击事件忽略空白像素区域

我们会遇到图片不是方形的不规则图片。这个时候我们希望只有点击到图像内容本身才算点击,点击空白区域则不算点击。而UGUI对图片的处理是整个图片都会算作点击区域,这样不能满足于我们的使用需求了。 首先我们需要把图片本身的Read/Write 选项打开 然后…

深入了解 NumPy:深度学习中的数学运算利器

文章目录 1. 导入NumPy2. 创建NumPy数组3. 数组的算术运算4. N维数组4.1 创建和操作多维数组4.2 高维数组 5. NumPy的广播功能5.1 基本广播示例5.2 更复杂的广播示例 6. 访问数组元素6.1 基于索引的访问6.2 遍历数组6.3 基于条件的访问6.4 高级索引6.5 性能考虑 在深度学习和数…

「C++ STL篇 1-0」string类的使用

目录 〇、概念 一、string类的构造函数 二、赋值运算符重载 三、有关容量的操作 四、string对象的访问 五、遍历string对象的字符数组 六、string对象的修改 七、string对象的常用操作 八、字符串和数字间的转换 拓展】 练习】 源代码】 〇、概念 1. string类是什么&#xff1…

如何查看Windows 10故障日志和错误日志?这里提供详细步骤

序言 当你的计算机崩溃时,会生成一个崩溃日志,可以帮助你分析崩溃的原因。但是,你知道如何查看Windows 10崩溃日志和错误日志吗?如果你不知道,别担心。这篇文章将向你展示如何使用两种方法查看Windows10崩溃日志。 使用事件查看器查看Windows 10故障日志 要查看Windows…

【Java】基本程序设计结构(一)

前言:现在,假定已经成功安装了JDK,并且能够运行上篇示例程序。本篇将开始介绍Java程序中的基本设计结构,其中包括:一个简单的Java应用,注释,数据类型,变量与常量,运算符&…

对于子数组问题的动态规划

前言 先讲讲我对于这个问题的理解吧 当谈到解决子数组问题时,动态规划(DP)是一个强大的工具,它在处理各种算法挑战时发挥着重要作用。动态规划是一种思想,它通过将问题分解成更小的子问题并以一种递归的方式解决它们,然后利用这些…

Linux(openEuler、CentOS8)基于chrony企业内网NTP服务器搭建实验

一、知识点 chrony 是由 守护进程 chronyd 以及 命令行工具 chronyc 组成的 chronyd 在后台静默运行并通过 123 端口与时间服务器定时同步时间,默认的配置文件是 /etc/chrony.conf chronyc 通过 323 端口与 chronyd 交互,可监控 chronyd 的性能并在运…

EPAI手绘建模APP资源管理和模型编辑器2

g) 矩形 图 26模型编辑器-矩形 i. 修改矩形的中心位置。 ii. 修改矩形的长度和宽度。 h) 正多边形 图 27模型编辑器-内接正多边形 图 28模型编辑器-外切正多边形 i. 修改正多边形的中心位置。 ii. 修改正多边形中心距离端点的长度。 iii. 修改正多边形的阶数。阶数为3&…

LLVM Instruction Selection 笔记

Instruction Selection 所处阶段 注:上图来源于 Welcome to the back-end: The LLVM machine representation 可以看到 SelectionDAG 架在 LLVM IR 和 LLVM MIR 之间,在此之前 machine independent optimization 已经完成。之后基本上就进入了 machine …

Dynamics 365: 从0到1了解如何创建Custom API(2) - Custom API与插件关联

接上一篇文章Dynamics 365: 从0到1了解如何创建Custom API(1) - 在Power Apps中创建-CSDN博客 这次我们主要写一个插件,与我们之前创建的Custom API进行关联。 1. 编写插件代码 因为代码太少了,我就不写注释了,大家如果有不懂的可以在评论…

2024牛客五一集训派对day5 K.Stack

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e18, maxm 4e4 5; c…

知乎23届数据分析校招A卷——笔记

1、and 和 or的并列运用[先看and] 条件1 OR 条件2 AND 条件3 执行顺序是先执行AND操作符&#xff08;先看条件2和3&#xff09;&#xff0c;再根据其结果判断是否需要执行OR操作符&#xff0c;并最终返回整个表达式的逻辑结果。 条件1 and 条件2 or 条件3 执行逻辑是先执行…

Swiper轮播图

版本&#xff1a;“swiper”: “^6.8.4”, 处理每分钟重新请求数据后&#xff0c;播放卡顿&#xff0c;快速闪&#xff0c;没按照设置时间播放等bug 以下是直接vue2 完整的组件代码 使用&#xff1a; <SwiperV :imgList“swiperList” / <template><div class"…

【论文阅读笔记】关于“二进制函数相似性检测”的调研(Security 22)

个人博客链接 注&#xff1a;部分内容参考自GPT生成的内容 [Security 22] 关于”二进制函数相似性检测“的调研&#xff08;个人阅读笔记&#xff09; 论文&#xff1a;《How Machine Learning Is Solving the Binary Function Similarity Problem》&#xff08;Usenix Securi…

docker-compose启动mysql5.7报错

描述一下问题经过&#xff1a; 使用docker compose 部署mysql5.7 文件如下: 使用命名卷的情况下&#xff0c;匿名卷不存在该问题 services:mysql:restart: alwaysimage: mysql:5.7container_name: mysql-devports:- 3306:3306environment:- MYSQL_DATABASEdev- MYSQL_ROOT_PAS…

备忘: 使用langchain结合千问大模型,用本地知识库辅助AI生成代码

本文主要是寻求解决把预先准备的文字需求转换为代码的方法 主要思路&#xff1a; 把某一类文字需求储存到本地知识库&#xff0c;使得用户输入需求目标&#xff0c;然后程序自动从知识库抽取相关需求&#xff0c;然后转发给在线的大模型形成代码。 工具&#xff1a; 本地在库用…

【UnityRPG游戏制作】Unity_RPG项目_玩法相关

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

jvm 马士兵 01 JVM简介,class文件结构

01.JVM是什么 JVM是一个跨平台的标准 JVM只识别class文件&#xff0c;符合JVM规范的class文件都可以被识别 u1 是一个字节 u2是两个字节

正则表达式_字符匹配/可选字符集

正则表达式&#xff08;Regular Expression&#xff09;也叫匹配模式(Pattern)&#xff0c;用来检验字符串是否满足特 定规则&#xff0c;或从字符串中捕获满足特定规则的子串。 字符匹配 最简单的正则表达式由“普通字符”和“通配符”组成。比如“Room\d\d\d”就这样 的正则…