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多路复用----本质上是一个线程负责处理多个客户端的请求。

相关推荐
A小辣椒1 天前
TShark:Wireshark CLI 功能
linux
A小辣椒1 天前
TShark:基础知识
linux
AlfredZhao1 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5203 天前
Linux 11 动态监控指令top
linux