javaSE————网络编程套接字

2025-04-17 0 317

网络编程套接字~~~~~

好久没更新啦,蓝桥杯爆掉了,从今天开始爆更嗷;

1,网络编程基础

为啥要有网络编程呢,我们进行网络通信就是为了获取丰富的网络资源,说实话真的很神奇,想想我们躺在床上,通过网络,访问到世界上成千上万的人做好的网络资源,我们甚至能看到一辈子都看不到的景色,这些资源本质上都是二进制资源或者是文本资源,我们通过网络可以让很多人来访问,这个就是网络编程,当年的网络就是个看报的,谁能想到发展到这样呢?

网络编程的概念:网络上的主机,通过不同的进程,以编程的方式实现网络通信;

同一个主机下的不同进程实现网络通信也是网络编程;

网络编程的基本概念:

接收端:数据接收端进程,目标主机;

发送端:数据发送端进程,源主机;

收发端:发送接收两端;

请求:请求数据的发送;

响应:响应数据的发送;

就像我们去餐厅点一份蛋炒饭就是请求,厨师给我们拿来蛋炒饭就是回应;

服务端:提供服务的一方,返回服务资源;

客户端:获取服务的一方;


2,Socket套接字

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

Socket套接字主要针对传输层协议划分为三类:

我们这里就学两个核心协议

1,TCP,有连接,可靠传输,面向字节流,全双工;

2,UDP,无连接,不可靠传输,面向数据报,全双工;

这里的有连接和无连接都是抽象的概念,虚拟上的连接;

TCP协议保存了对端的信息,A和B通信,A和B先建立连接,A保存了B的信息,B也保存了A的信息,他们彼此都知道谁与自己建立的连接,而UDP不保存对方的信息;

可靠传输和不可靠传输是什么呢?

网络上,数据的传输是会发生丢包的情况的,可能会受到外界的干扰,那么可靠传输就能避免这样的丢包吗,事实上是不能的,可靠传输只是保证尽可能提高传输成功的概率,如果出现了丢包,也能感知到,不可靠传输的话就是把数据发送之后就不管了,那么这样的话我们就使用可靠传输就好了呀,还要UDP干嘛呢,凡是必有代价,UDP的话速度会更快;

面向字节流和面向数据报呢?

面向字节流:读写数据的时候,以字节为单位;

面向数据报:读写数据的时候,以一个数据报为单位;

全双工和半双工呢?

全双工:一个通信联络,能读也能写;

半双工:只支持单向通信,要么读,要么写;

我们使用Socket api来进行网络编程,我们之前提到计算机中的“文件”有狭义和广义的概念,硬件设备可以抽象成文件,统一管理;电脑上的网卡就是Socket文件;


3,UDP数据报套接字编程

我们先来介绍UDP需要的API:

DatagramSocket

UDP的Socket用于接收和发送UDP数据报;

构造方法:

方法签名 方法说明
DatagramSocket() 创建一个UDP数据报套接字的Socket,绑定到本机任意一个端口,一般用于客户端
DatagramSocket(int port) 创建一个UDP数据报套接字的Socket,绑定到本机指定的端口,一般用于服务端

方法:

方法签名 方法说明
void receive(DatagramPacket p) 从此套接字接收数据报,如果没有收到数据报就会阻塞等待;
void send(DatagramPacket p) 从此套接字发送数据报,不会阻塞等待,直接发送;
void close() 关闭此数据报套接字

DatagramPacket

datagramPacket是UDP socket发送和接收的数据报;

构造方法:

方法签名 方法说明
DatagramPacket(byte[] bytes, int length)

构造一个DatagramPacket用来接收数据报,接收的数据呢保存在字节数组中,接收指定的长度

DatagramPacket(byte[] bytes, int offset, int length, SocketAddress address) 构造一个DatagramPacket用来发送数据报,发送的数据为字节数组,从0开始,到指定长度,address指定制定目的主机的IP和端口号

方法:

方法签名 方法说明
InetAddress  getAddress()

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

int getPort() 从接收的数据报中,获取接收端主机的端口号;或者从发送的数据报中,或缺发送端主机的端口号;
byte[] getData() 获取数据报中的数据; 
getSocketAddress() 直接获取到当前数据报的IP和端口号;

 

讲完方法了,我们来模拟一个回显服务器,这里就是模拟,回显服务器就是自问自答;

我们来用UDP模拟一下:

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

public class UdpEchoServer {
    private DatagramSocket socket = null;
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);//指定端口号,让服务器来使用
    }
    public void start() throws IOException {
        //启动服务器
        while(true){
            //循环一次,就意味着处理了一次请求
            //1读取请求并解析
            DatagramPacket packet = new DatagramPacket(new byte[4090],4090);
            socket.receive(packet);
            String request = new String(packet.getData(),0,packet.getLength());
            //2根据请求计算响应
            String response = process(request);
            //3把响应返回给客户端
            DatagramPacket packet1 = new DatagramPacket(response.getBytes(),response.getBytes().length
            ,packet.getSocketAddress());
            socket.send(packet1);
            //4打印日志
            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 {
        UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
        udpEchoServer.start();
    }
}

模拟服务器:难点用注释标注了,看不明白就来私信我! 

接下来实现客户端代码:

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

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String SeverIp;
    private int SeverPort;
    public UdpEchoClient(String IP,int port) throws SocketException {
        this.SeverIp = IP;
        this.SeverPort = port;
        socket = new DatagramSocket();
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while(true){
            System.out.println("请输入要发送的内容");
            while(!scanner.hasNext()){
                break;
            }
            String request = scanner.nextLine();
            DatagramPacket datagramPacket = new DatagramPacket(request.getBytes(),request.getBytes().length
            , InetAddress.getByName(SeverIp),SeverPort);
            socket.send(datagramPacket);

            DatagramPacket datagramPacket1 = new DatagramPacket(new byte[4090],4090);
            socket.receive(datagramPacket1);

            String response = new String(datagramPacket1.getData(),0,datagramPacket1.getLength());
            System.out.println(response);
        }
    }

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

}

我们把两个代码的都运行下javaSE————网络编程套接字 

客户端

javaSE————网络编程套接字

服务器


4,TCP流套接字编程

接下来我们来实现TCP的网络编程,还是先来学习一下方法:

SeverSocket

SeverSocket呢是创建TCP服务端Socket的ApI;

构造方法:

方法签名 方法说明
SeverSocket(int port) 创建一个服务端流套接字Socket,并绑定到指定端口

方法:

方法签名 方法说明
Socket accept() 开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待;
void close() 关闭此套接字;

Socket

socket是客户端Socket,或服务端中接收到客户端建立连接(accept)的请求后,返回的服务端Socket;

构造方法:

方法签名 方法说明
Socket(String host,int port) 创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接;

方法:

方法签名 方法说明
inerAddress  getInetAddress() 返回套接字所连接的地址
inputStream  getInputStream() 返回此套接字的输入流
OutputStream  getOutputStream() 返回此套接字的输出流

服务端

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 executorService = Executors.newCachedThreadPool();
        while(true){
            Socket socketClient = serverSocket.accept();
            executorService.submit(()->{
                try {
                    processConnection(socketClient);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

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

    public String process(String request){
        return request;
    }

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

这里引入线程池来处理多个请求,避免其他请求发来处理不了的情况;

客户端:
 

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
    private Socket socket = null;
    public TcpEchoClient(String IP,int port) throws IOException {
        socket = new Socket(IP,port);
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()){
            Scanner scanner1 = new Scanner(inputStream);
            PrintWriter printWriter = new PrintWriter(outputStream);

            while(true){
                System.out.println("请输入要发送的信息");
                String request = scanner.nextLine();
                printWriter.println(request);
                printWriter.flush();
                String response = scanner1.nextLine();
                System.out.println(response);
            }
        }
    }

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

平台声明:以上文章转载于《CSDN》,文章全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,仅作参考。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/2301_79083481/article/details/147311719

遇见资源网 JAVA javaSE————网络编程套接字 http://www.ox520.com/157768.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务