关于网络编程

news2024/11/17 11:40:42

Socket套接字

Socket API是网络编程最核心的部分。

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

Socket API与传输层密切相关,由于传输层有UDP和TCP两种协议类型,故Socket API也提供了两种风格(准确来说有三种,Unix域套接字不常用或者说很早就没人用了)。

Socket套接字的分类

主要根据传输层协议划分为三类:

流套接字

使用TCP传输协议。

特点:

  • 有连接

  • 可靠传输

  • 面向字节流 ——>数据传输文件读写类似于“流式”。

  • 有接收缓冲区,有发送缓冲区

  • 大小无限制

数据套接字

使用传输层UDP协议。

特点:

  • 无连接

  • 不可靠传输

  • 面向数据报——>数据传输是以一个个“数据报”为基本单位(一个数据报可能是若干个字节)

  • 有接收缓冲区,无发送缓冲区

  • 大小有限制

原始套接字

不做了解。

此处的可靠传输和不可靠传输与有连接和无连接无关。

流套接字和数据套接字都是全双工的,可以双向传输。


UDP数据报套接字

DatagramSocket API

表示一个Socket文件。

普通的文件对应的硬件设备是硬盘,Socket文件对应的硬件设备是网卡。

DatagramSocket的构造方法

一个socket对象就可以和另一台主机进行通信。同样的,要与多台主机进行通信需要有多个socket对象。

没有指定端口,系统会给自动分配一个空闲的端口。

port指定了端口。此时就是让当前的socket对象与指定端口关联起来。

端口号一般是简单的整数

本质上,不是进程和端口建立了联系而是进程中的socket对象和端口建立了联系。

DatagramSocket的方法

此处传入的相当于是一个空的对象,receive方法内部会对参数(这个对象)进行内容的填充,从而构造出结果数据。

如果没有接收到数据报,该方法会阻塞等待。

传入的参数是下面要说的,报文。

关闭这个socket文件释放资源。

DatagramPacket API

表示UDP中传输的一个报文。

DatagramPacket是UDP Socket发送和接收的数据报,构造这个对象可以指定一些具体的数据进去。

DatagramPacket的构造方法:

其中常用的构造方法为:

接收

发送

address指定了目的主机的IP和端口号。

DatagramPacket的方法:

对于UDP来说,DatagramPacket是传输数据的基本单位。而在上述的方法中,日常使用的为以下三种方法。

方法名

方法说明

InetAddress getAddress()

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

从发送的数据报中,获取接收端主机的IP地址。

int getPort()

从接收的数据报中获得发送端主机的端口号;

从发送的数据报中获得接收端主机的端口号。

byte[] getData()

获取数据报中的数据

在构造UDP发送的数据报时,需要传入socketAddress,这个对象可以用InetSocketAddress来创建。

DatagramPacket.getSocketAddress()

获取要将此包发送到的或发出此数据报的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)。

InetSocketAddress API

InetSocketAddress 的构造方法

方法名

方法说明

InetSocketAddress(InetAddress addr,int port)

创建一个socket地址,包含IP地址和端口号


TCP流套接字

ServerSocket API

ServerSocket的构造方法

方法名

方法说明

ServerSocket(int port)

创建一个服务端流套接字Socket,并绑定到指定的端口上。

客户端在构造Socket对象的时候,会指定服务器的IP和端口。

ServerSocket方法

方法名

方法说明

Socket accept()

开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待。

void close()

关闭此套接字

对于Socket accept()这个方法是调用一个接通一个,相当于接电话,要先建立连接才能进行通信。返回服务端Socket的前提得有客户端来建立连接,如果没有客户端来建立连接,此时这个方法就会阻塞等待。

Socket API

Socket既给客户端使用也给服务器使用。

在服务器这边,是由accept返回的。

在客户端这边,是在代码中构造出来的,构造的时候,指定一个IP和端口号(此处指定的IP和端口号是服务器的IP和端口号。)

无论是服务器还是客户端Socket都是双方建立连接之后,保存的对端信息,用来与对方收发数据的。

Socket构造方法

方法名

方法说明

Socket(String host,int port)

创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接。

Socket方法

方法名

方法说明

InetAddress getInetAddress()

返回套接字所连接的地址

InputStream getInputStream()

返回此套接字的输入流

OutputStream getOutputStream()

返回此套接字的输出流

InputStream getInputStream()和OutputStream getOutputStream() 进一步通过Socket对象获取到内部的流对象,通过流对象进行发送/接收。


回显服务器

首先理解什么是服务器:

一般的服务器收到请求后会根据请求计算响应,并将响应返回。

而回显服务器则是省略了其中“根据请求计算响应”这个步骤,也就是说,请求是什么,返回的响应也是什么。

UDP回显服务器的实现:

UDP回显服务器客户端实现:
import javafx.scene.transform.Scale;

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

public class EchoClient {
    private String serverIp=null;
    private int serverPort=0;
    private DatagramSocket socket=null;

    public EchoClient(String serverIp,int serverPort) throws SocketException {
        socket=new DatagramSocket();
        this.serverIp=serverIp;
        this.serverPort=serverPort;
    }
    public void start() throws IOException {
        System.out.println("客户端启动!");
        Scanner scanner=new Scanner(System.in);
        while(true){
            System.out.println(">");
            String request=scanner.next();
            if(request.equals("exit")){
                System.out.println("goodbye");
                break;
            }
        
            DatagramPacket datagramPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);
            socket.send(datagramPacket);
            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 {
        EchoClient echoClient=new EchoClient("127.0.0.1",9090);
        echoClient.start();
    }
}
UDP回显服务器实现:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class EchoServer {
     private DatagramSocket socket=null;
    public  EchoServer(int port) throws SocketException {
         socket=new DatagramSocket(port);
     }
     public void start() throws IOException {
         System.out.println("服务器启动");
         while(true){
             DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
             socket.receive(requestPacket);
             String request=new String(requestPacket.getData(),0,requestPacket.getLength());
             String response=process(request);
             DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
             socket.send(responsePacket);
             System.out.printf("[%s:%d] req:%s;resp:%s\n",requestPacket.getAddress().toString(),
                     requestPacket.getPort(),request,response);
         }
     }
    public String process(String request) {
         return request;
    }

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

}

TCP回显服务器的实现:

TCP回显服务器客户端实现:
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 {
        socket=new Socket(serverIp,serverPort);
    }

    public void start() {
        System.out.println("客户端启动");
        Scanner scanner=new Scanner(System.in);
        try(InputStream inputStream=socket.getInputStream();
            OutputStream outputStream=socket.getOutputStream()) {
            while(true){
                System.out.print(">");
                String request=scanner.next();
                if(request.equals("exit")){
                    System.out.println("GoodBye");
                    break;
                }
                PrintWriter printWriter=new PrintWriter(outputStream);
                printWriter.println(request);
                printWriter.flush();
                Scanner respScanner=new Scanner(inputStream);
                String response=respScanner.next();
                System.out.println(response);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client=new TcpEchoClient("127.0.0.1",9090);
        client.start();
    }
}
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;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {
    private ServerSocket serverSocket=null;
    public TcpEchoServer(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("启动服务器");
        ExecutorService threadPool= Executors.newCachedThreadPool();
        while(true){
            Socket clientSocket= serverSocket.accept();
            threadPool.submit(()->{
                processConnection(clientSocket);
            });
        }
    }

    private void processConnection(Socket clientSocket) {
        System.out.printf("[%s:%d]客户端上线",clientSocket.getInetAddress().toString(),clientSocket.getPort());
       try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()) {
            while(true){
                Scanner scanner=new Scanner(inputStream);
                if(!scanner.hasNext()){
                    System.out.printf("[%s:%d]客户端下线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
                    break;
                }
                String request=scanner.next();
                String response=process(request);
                PrintWriter printWriter=new PrintWriter(outputStream);
                printWriter.println(response);
                printWriter.flush();
                System.out.printf("[%s:%d]req:%s;resp:%s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),
                        request,response);
            }
        } catch (IOException e) {
           e.printStackTrace();
        } finally {
            try {
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public String process(String request){

        return request;
    }

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

客户端和服务器:

一般对服务器的端口号要求是明确的(为了方便客户端找到服务器程序),而对客户端的端口是不指定要求的(客户端如果显式指定端口,可能会出现当前指定的端口和客户端电脑上其他程序的端口冲突这样的问题,这一问题可能会导致程序无法正确通信。

对于服务器发给客户端这个操作来说:服务器的端口就是源端口,客户端的端口是目的端口。

而对于客户端发给服务器这个操作来说:服务器的端口就是目的端口,客户端的端口号是源端口。

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

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

相关文章

使用Idea中将单个java类打包成jar包

开工第一天,正在暗自爽,领导让帮个忙,给一个工具类打成jar包,供其他项目组使用,这就开始了尝试。 其实网上已经有好多人写过了,只是尝试了几篇,坑得不轻,自己做下笔记,留…

表格控件Aspose.Cells for .NET 授权须知

支持的平台 Aspose.Cells 可作为 .NET、Java、C 和 Python 的四种不同产品使用, .NET Framework.NET Standard 2.0Xamarin.AndroidXamarin.iOSXamarin.MacCOMMonoWindows Azure Aspose.Cells 下载(qun:761297826)https://www.ev…

python 高阶函数

传入函数 要理解“函数本身也可以作为参数传入”,可以从Python内建的map/reduce函数入手。 我们先看map。map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的l…

Java:基于注解的Spring使用【AOP容器】和事务管理

目录 第十五章 AOP前奏15.1 代理模式15.2 为什么需要代理【程序中】15.3 手动实现动态代理环境搭建15.4 手动实现动态代理关键步骤第十六章 Spring中AOP【重点】16.1 AspectJ框架【AOP框架】16.2 使用AspectJ步骤(入门)16.3 Spring中AOP概述16.4 Spring中…

AMQP 0-9-1 模型解释

官方文档链接:https://www.rabbitmq.com/tutorials/amqp-concepts.html 文章目录1. AMQP协议是什么2. AMQP模型2.1 工作过程2.2 深入理解3. 交换机3.1 默认交换机3.2 直连交换机3.3 扇形交换机3.4 主题交换机3.5 头交换机3.6 交换机小结4. Queue队列队列属性队列创建…

BM7 链表中环的入口结点

目录 描述 输入描述: 返回值描述: 示例1 示例2 示例3 思路: 代码 描述 给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。 例如,输入{1,…

DW 2023年1月Free Excel 第九次打卡 Excel数据透视

第九章 Excel数据透视 数据下载地址与参考链接:https://d9ty988ekq.feishu.cn/docx/Wdqld1mVroyTJmxicTTcrfXYnDd 数据透视是Excel中个强大的数据处理和分析工具,能够快速实现数据的汇总与统计分析,本节重点讲解Excel数据透视的相关操作。 1…

NSSCTF Round#7 Team ez_rce和0o0讲解

强烈建议NSSCTF延长时间&#xff0c;大过年的逛亲戚回来就剩两个小时了。。。。 ez_rce <!-- A EZ RCE IN REALWORLD _ FROM CHINA.TW --> <!-- By 探姬 --> <?PHPif(!isset($_POST["action"]) && !isset($_POST["data"]))show_s…

MySQL8中jdbc的url设置

JDBC spring.datasource.urljdbc:mysql://${MYSQL_HOST:localhost}:3306/xxxx?sslModeREQUIRED&characterEncodingUTF-8&connectionTimeZoneGMT%2B8&forceConnectionTimeZoneToSessiontruesslMode:设置为REQUIRED表示必须启用ssl加密传输&#xff1b;characterEn…

svn客户端add无法添加上子文件夹及其子文件——解决办法

1、问题描述 svn客户端add文件夹后&#xff0c;无法添加上子文件夹及其子文件&#xff0c;需要先add最外层文件夹&#xff0c;再逐层add子文件夹&#xff0c;最后add最里层子文件夹中的文件&#xff0c;很影响add速度啊。现象如下图所示&#xff1a; 正常情况下&#xff0c;add…

公派访问学者申请优势有哪些?

人的一生&#xff0c;若从职业生涯论&#xff0c;无非为官、为学、为商三条路。为官者&#xff0c;出国访学一年半载&#xff0c;对仕途并无太大作用&#xff0c;并且在此期间有可能丧失国内提拔的大好机会;为学者&#xff0c;公派访问学者是对学术水平的认可&#xff0c;并且对…

vue.js 实现导入json解析成动态el-table树表格(接口文档功能)

一、需求描述&#xff1a;前段时间接到一个需求是做一个类似接口文档的显示功能&#xff0c;将一段json数据贴到里面就可以自动解析出json数据的每个字段的类型和层级关系&#xff0c;用element组件的树表格的形式展示&#xff0c;并且可以手动新增、修改和删除某个数据字段。二…

Vue路由和路由器简介

前言 路由(route)是vue中非常重要的技术&#xff0c;几乎每一个用vue所写的项目都会用到路由&#xff0c;它是一个vue的插件库&#xff0c;专门实现SPA应用 路由(route)的简介 说到路由&#xff0c;大多数人会想到路由器(router),可以这么说&#xff0c;路由器上的每一个口都…

Python类变量和实例变量

类变量&#xff08;类属性&#xff09;类变量指的是在类中&#xff0c;但在各个类方法外定义的变量。举个例子&#xff1a;class CLanguage : # 下面定义了2个类变量name "CSDN社区"add "http://csdn.net" # 下面定义了一个say实例方法 defsay(self, conte…

【Linux】进程信号的产生与捕捉、核心转储

目录 一、信号的引入 二、信号捕捉 三、核心转储 四、系统调用发送信号 五、软件条件产生信号 六、硬件异常产生信号 一、信号的引入 Linux信号本质是一种通知机制&#xff0c;用户 or 操作系统通过发送一定的信号&#xff0c;通知进程&#xff0c;某些事件已经发生&…

JavaWeb-MyBatis | Mapper代理开发及案例

本专栏主要是记录学习完JavaSE后学习JavaWeb部分的一些知识点总结以及遇到的一些问题等&#xff0c;如果刚开始学习Java的小伙伴可以点击下方连接查看专栏 本专栏地址&#xff1a;&#x1f525;JDBC Java入门篇&#xff1a; &#x1f525;Java基础学习篇 Java进阶学习篇&#x…

【5G NTN】5G NTN(非地面组网)介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

DTD语法详细介绍

在编写XML文档时&#xff0c;需要掌握XML语法。同理&#xff0c;在编写DTD文档时&#xff0c;也需要遵循一定的语法。DTD的结构一般由元素类型定义、属性定义、实体定义、记号(notation)定义等构成&#xff0c;一个典型的文档类型定义会把将来要创建的XML文档的元素结构、属性类…

LeetCode Hot100 ---- 双指针算法专题

167, 88, 142, 76双指针双指针法&#xff0c;有时也叫快慢指针&#xff0c;在数组里是用两个整型值代表下标&#xff0c;在链表里是两个指针&#xff0c;一般能实现O(n)的时间解决问题&#xff0c;两个指针的位置一般在第一个元素和第二个元素或者第一个元素和最后一个元素&…

【Leetcode每日一题】844. 比较含退格的字符串|重构字符串/双指针

博主简介&#xff1a;努力学习的预备程序媛一枚~博主主页&#xff1a; 是瑶瑶子啦所属专栏: LeetCode每日一题–进击大厂 前言&#xff1a; 昨天的【Leetcode每日一题】27. 原地移除元素|神级理解双指针一文中&#xff0c;生动形象的为大家讲解如何理解双指针&#xff0c;受到…