JavaEE初阶 --网络编程

一.为什么要网络编程?

用户在浏览器,打开视频网站时,实际是通过网络获取到的网络资源,所有的网络资源都是通过网络编程进行数据传输的。

二.Socket套接字

1.概念

Socket套接字本质上是一个编程接口,是由传输层给应用层提供的。当俩台设备进行通信时,Socket内部封装了通信的五元组。内核通过五元组唯一标识一条路径,确保数据能够准确送达到指定设备(目的IP)的指定进程(目的端口)。

2.分类

我们主要学习的是流套接字(使用传输层TCP协议)和数据报套接字(使用传输层UDP协议)

1)数据包套接字

特点:无连接,面向数据包,不可靠传输,全双工,有接受缓冲区,无发送缓冲区.一次最多传送64kb(讲UDP的结构可知道)

2)流套接字

**特点:**有连接,面向字节流,可靠传输,全双工,既有接受缓冲区又有发送缓冲区,传输数据大小不限。

3.名词解释

1)有连接和无连接

这里的连接是逻辑上的连接,而不是物理上的连接。在TCP协议中,如果设备A和设备B进行通信就得先建立连接,让A保存B的相关信息,B也保存A的相关信息,彼此之间知道自己连接的是谁。在UDP协议中,是无连接,俩台设备不会保存对端的相关信息,直接根据五元组中的目标IP和端口转发数据包,因此无需建立链路也能通信。

2)可靠传输和不可靠传输

网络上,是非常容易出现数据丢失的情况(丢包)如光信号和电信号容易遭受到外部环境的影响。

可靠传输的意思不是让数据100%到达目的地,而是在出现丢包的情况下能够知道,然后在一定条件下进行重传。而不可靠传输是把数据发出去后就直接不管了

3)面向字节流和面像数据报

面向字节流代表传输数据的基本单位为字节,但会出现粘包问题(讲TCP的结构会讲)

面向数据报代表传输数据的基本单位为数据报,不会出现粘包问题。

4)全双工和半双工

全双工代表双向通信(既能读又能写)

半双工代表单向通信(要么读要么写)

总结: 对于 TCP 而言,通信前需要通过三次握手(TCP协议会讲)在内核中建立一条逻辑链路 (即维持双方的状态同步),以保证可靠传输;而对于 UDP,内核不维护对端状态,直接根据五元组中的目标地址转发数据包,因此无需建立链路也能通信。

三.网络编程

1.UDP数据报套接字编程

API介绍

1)DatagramSocket

是UDP Socket,用于发送和接受UDP数据包

构造方法:
普通方法:
2)DatagramPacket

是UDP Socket发送和接受的数据报

构造方式:
普通方法:

使用:

代码:

java 复制代码
import java.io.IOException;
import java.net.*;

public class UDPEchoServer {
    private DatagramSocket socket =null;
    //指定ip
    public UDPEchoServer(String ip, int port)
            throws UnknownHostException, SocketException {
        socket =new DatagramSocket(port,InetAddress.getByName(ip));
    }
    //不指定ip,代表绑定本机所有ip
    public UDPEchoServer(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);

//       处理请求,把字节数组转化为字符串形式,这里得传有效长度,不能传requestPacket.getData().length
          String request =new String(requestPacket.getData(),0, requestPacket.getLength());
           String response = process(request);
//        响应请求
           DatagramPacket responsePacket =new DatagramPacket(
                   response.getBytes(),response.getBytes().length,//这里传的是字节数,不能传response.length
                   requestPacket.getAddress(),requestPacket.getPort());
           socket.send(responsePacket);
           System.out.println("客户端"+requestPacket.getPort()+requestPacket.getAddress()+"发出请求");
           System.out.printf("回复:%s\n",response);
       }

    }

    private String process(String request) {
        //为回显服务器,不做处理
        return request;
    }


    public static void main(String[] args) throws IOException {
        UDPEchoServer echoServer =new UDPEchoServer(9090);
        echoServer.start();
    }
}
java 复制代码
import java.io.IOException;
import java.net.*;
import java.util.Scanner;

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

    public UDPEchoClient(String serverIp, int serverPort) throws SocketException {
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        //找空闲端口
        socket =new DatagramSocket();
    }

    public void start() throws IOException {

        Scanner scanner =new Scanner(System.in);
        while (true){
            //用户输入请求
            String request = scanner.next();
            //发送请求
            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:"+response);
        }
    }

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

2.TCP套接字编程

API介绍

1)ServerSocket

是创建TCP服务端Socket

构造方法:
普通方法:

2)Socket

Socket 是客⼾端Socket,或服务端中接收到客⼾端建⽴连接(accept⽅法)的请求后,返回的服 务端Socket。 不管是客⼾端还是服务端Socket,都是双⽅建⽴连接以后,保存的对端信息,及⽤来与对⽅收发数据 的。

构造方法:
普通方法:

使用:

代码:

java 复制代码
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.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TCPEchoServer {
    private ServerSocket socket =null;

    public TCPEchoServer(int port) throws IOException {
        socket =new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务端启动");
        ExecutorService executorService = Executors.newCachedThreadPool();
        //每一个连接处理一个客户端
        while (true){
            Socket clientSocket = socket.accept();
            executorService.submit(()->{
                System.out.println("客户端启动:"+
                        clientSocket.getInetAddress()+" "+clientSocket.getPort());
                processConnect(clientSocket);
            });
        }
//        while (true){
//            Socket clientSocket = socket.accept();
//            Thread thread =new Thread(()->{
//                System.out.println("客户端启动:"+
//                        clientSocket.getInetAddress()+" "+clientSocket.getPort());
//                processConnect(clientSocket);
//            });
//            thread.start();
//        }
    }

    private void processConnect(Socket clientSocket) {
        try(InputStream inputStream =clientSocket.getInputStream();
                OutputStream outputStream =clientSocket.getOutputStream()){
            Scanner scanner =new Scanner(inputStream);
            PrintWriter writer =new PrintWriter(outputStream);

            while (true){
                if(!scanner.hasNext()){
                    System.out.println("客户端退出:"+
                            clientSocket.getInetAddress()+" "+clientSocket.getPort());
                    break;
                }
                String request =scanner.next();
                String response =process(request);
                writer.println(response);
                writer.flush();
                System.out.println("客户端"+clientSocket.getInetAddress()+" "+
                        clientSocket.getPort()+"发来请求");
                System.out.println("回复:"+response);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                clientSocket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

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

    public static void main(String[] args) throws IOException {
        TCPEchoServer server =new TCPEchoServer(9090);
        server.start();
    }
}
java 复制代码
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 clientSocket =null;

    public TCPEchoClient(String serverIp,int serverPort) throws IOException {
        clientSocket =new Socket(serverIp,serverPort);
        System.out.println("客户端上线:"+clientSocket.getLocalAddress()+
                " "+clientSocket.getLocalPort());
    }
    public void start(){
        try(InputStream inputStream =clientSocket.getInputStream();
            OutputStream outputStream =clientSocket.getOutputStream()){
            Scanner scannerRead =new Scanner(inputStream);
            PrintWriter writer =new PrintWriter(outputStream);
            Scanner scannerWrite =new Scanner(System.in);

            while (true){
                System.out.println("请输入请求---》");
                String request =scannerWrite.next();
                writer.println(request);
                writer.flush();
                String response =scannerRead.next();
                System.out.println("回复:"+response);

            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

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

注意:如果客户端进一步增加,就会产生大量的线程。为了处理这个问题,操作系统内部内置了IO多路复用----本质上是一个线程负责处理多个客户端的请求。

相关推荐
Cyber4K2 小时前
【妙招系列】Harbor 镜像私有仓库搭建手册
linux·云原生·容器
Oll Correct2 小时前
实验八:验证以太网交换机的生成树协议STP
网络·笔记
Irissgwe3 小时前
进程间通信
linux·服务器·网络·c++·进程间通信
创世宇图3 小时前
阿里云Alibaba Cloud Linux 4 LTS 64位生产环境配置-Nginx
linux·nginx
岁岁种桃花儿3 小时前
AI超级智能开发系列从入门到上天第四篇:AI应用方案设计
java·服务器·开发语言
待续3014 小时前
OpenClaw 安装及使用教程(Windows / macOS / Linux)
linux·windows·macos
创世宇图4 小时前
Alibaba Cloud Linux 安装生产环境-mysql
linux·mysql
TEC_INO4 小时前
嵌入式 Linux 开发知识总结
linux·运维·服务器
IT小白34 小时前
windows的VMware虚拟机上的Linux系统(CentOS)配置永久ip(关机重启ip不变)
网络·网络协议·tcp/ip