Java:TCP/UDP网络编程

发布于:2025-08-31 ⋅ 阅读:(23) ⋅ 点赞:(0)

目录

一、前言

1、计算机网络

2、软件结构

3、通信三要素

二、TCP和UDP简单介绍

TCP的三次握手四次挥手

三、TCP网络编程

1、通信流程

2、构造方法

3、基础案例

4、多线程反转案例

5、传输对象

四、UDP网络编程


一、前言

        网络编程的历史可以追溯到20世纪60年代,当时美国国防部高级研究计划局(ARPA)开发了ARPANET,这是互联网的前身。1983年,TCP/IP协议成为ARPANET的标准协议,奠定了现代互联网的基础

        Java的网络编程能力让开发者能够轻松构建客户端和服务器端应用程序,这也是Java在企业级应用中广泛使用的重要原因之一

        

        网络编程作用就是:

        通过编程的方式,使得计算机网络中不同计算机上的应用程序间能够进行数据的传输

1、计算机网络

        最简单的计算机网络:

        两台计算机,连接它们的一条链路

所以计算机网络其实就是

利用通信线路将分散在各个不同地方的、具有独立计算功能的计算机系统和通信设备

按照不同的形式连接起来

以功能完善的网络软件及协议实现资源共享和信息传递的系统

2、软件结构

常见的主要有 C/S B/S

Client / Server :

        客户端 / 服务器 的软件结构

        eg:QQ、微信、等各种软件,只要是我们下载安装的并且和服务器通信的

        都属于 C/S 软件结构

Browser / Server :

        浏览器 / 服务器 的软件结构

        eg:淘宝网、凤凰网、4399等,只要是使用浏览器并且和服务器通信的

        都属于 B/S 软件结构

C/S 和 B/S 对比:

1、CS图形表现及运行速度 > BS

2、CS需要客户端,不能跨平台,不同的操作系统安装包不一样

      BS不需要客服端,只要浏览器即可,BS基于网页语言,与操作系统无关,可以跨平台

3、通信三要素

  • IP地址:

域名:本质上也是ip,只是为了让ip更好记忆

           就是那些 www.xxx.com 网址

  • 端口:

端口号可以用来标识计算机中唯一的那个应用程序

一台计算机中的应用的端口号不能重复

常见端口号:

  •         80端口:前端的静态服务器
  •                 网页服务一般都是80端口
  •                 所以80可以省略
  •         BS架构的默认端口号是80,可以省略
  •         HTTP占用80
  •         FTP占用21 文件传输服务
  •         MySQL用3306
  •         oracle启动后默认占用端口号1521
  •         redis启动后默认占用端口号6379
  •         tomcat启动后默认占用端口号8080

  • 协议:

计算机与计算机通过网络进行数据和信息交换的时候

也要使用同样的“语言”,这个语言被称为网络通讯协议。

通信双方必须同时遵守才能完成数据交换,常见的协议有UDP协议和TCP协议

接下来进入本篇文章重点:

二、TCP和UDP简单介绍

完整的通信过程比较复杂

不过JavaAPI帮我们进行了细节的封装

给我们提供了类和接口直接使用

十分便利

java.net包 对这两种常见的通信协议进行了封装

UDP(不常用)
            传输层协议
            无连接通信协议

            在数据传输时,数据的发送端和接收端不建立连接,也不能保证对方能成功接收
            优点:
                通信效率高
            缺点:
                不能保证数据传输的成功率和完整性

        

TCP(重点)
            传输层协议

            面向连接
            优点:可靠的,无差错的
            缺点:效率低

            针对客户端和服务器,都进行了抽象:
                客户端:java.net.Socket
                服务器:java.net.ServerSocket

TCP的三次握手四次挥手

三次握手(建立连接):

  1. 客户端向服务端发送连接请求
  2. 服务端收到请求后向客户端发送确认
  3. 客户端收到服务端发来的确认信息后,向服务端发送确认收到的信息

四次挥手(断开连接):

  1. 客户端向服务端发送断开请求
  2. 服务端收到断开请求后,向客户端发送确认信息
  3. 服务端处理完剩余数据后,向客户端发送断开请求
  4. 客户端收到服务端的断开请求后,向服务端发送确认断开信息,然后客户端进入TIME_WAIT状态开始等待,等待2MSL时间后确保连接断开(服务端无需等待直接关闭)

三、TCP网络编程

  • java.net.ServerSocket 类表示服务端
  • java.net.Socket 类表示客户端

1、通信流程

服务器端:

  • 创建ServerSocket(需要绑定端口号,方便客户连接)
  • 调用ServerSocket对象的 accept() 方法接收一个客户端请求,得到一个Socket
  • 调用Socket的 getInputStream() getOutputStream() 方法获取和客户端相连的IO流

输入流读取客户端发来的数据

输出流发送数据到客户端

  • 操作完成,关闭资源

客户端:

  • 创建Socket连接服务端(需指定服务器ip地址、端口),找对应的服务器进 行连接
  • 调用Socket的 getInputStream() getOutputStream() 方法获取和服务端相连的 IO流

输入流可以读取服务端输出流写出的数据

输出流可以写出数据到服务端的输入流

  • 操作完成,关闭资源

整个过程中

服务器不能主动连接客户端

必须等客户端先发起连接

2、构造方法

Socket socket2 = new Socket(InetAddress.getByName("www.baidu.com"), 80);

Socket socket = new Socket("www.baidu.com", 80);

3、基础案例

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TestSocket {
    public static void main(String[] args) throws IOException {
        String ip = "127.0.0.1";
        int port = 8888;

        Socket socket = new Socket(ip, port);
        System.out.println("成功连接:" + socket);

        InputStream is = socket.getInputStream();
        OutputStream os = socket.getOutputStream();

        //传输数据给服务器
        os.write("hello server,我是客户端".getBytes());
        // 刷新缓冲区
        os.flush();

        byte[] bytes = new byte[1024];
        int len = is.read(bytes);
        System.out.println("服务器说:" + new String(bytes, 0, len));
        
        os.close();
        is.close();

        socket.close();
    }
}


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TestServerSocket {
    public static void main(String[] args) throws IOException {
        int port = 8888;

        ServerSocket server = new ServerSocket(port);
        System.out.println("服务器启动成功,等待客户端连接,端口:" + port);

        System.out.println("server:" + server);
        // 等待客户端连接,这里终端会阻塞
        Socket socket = server.accept();
        System.out.println("socket:" + socket);

        InputStream is = socket.getInputStream();
        OutputStream os = socket.getOutputStream();

        byte[] bytes = new byte[1024];
        int len = is.read(bytes);
        System.out.println("客户端说:" + new String(bytes, 0, len));

        os.write("hello client,我是服务器".getBytes());
        os.flush();
        
        os.close();
        is.close();
        socket.close();
        server.close();
    }
}

4、多线程反转案例

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServerSocket {
    public static void main(String[] args) {
        int port = 8989;
        try {
            ServerSocket server = new ServerSocket(port);
            
            while(true){
                Socket socket  = server.accept();
                Thread t = new Thread(new Runnable() {
                    public void run() {
                        try {
                            InputStream is = socket.getInputStream();
                            OutputStream os = socket.getOutputStream();

                            byte[] buffer = new byte[1024];
                            int len;
                            while((len = is.read(buffer)) != -1){
                                String msg = new String(buffer, 0, len);
                                System.out.println("客户端说:" + msg);

                                if(msg.equals("quit")){
                                    break;
                                }

                                // 反转字符串
                                String reverse = new StringBuffer(msg).reverse().toString();
                                os.write(reverse.getBytes());
                                os.flush();
                            }
                            socket.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
                t.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class MySocket {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1", 8989);
            Scanner sc = new Scanner(System.in);

            OutputStream os = socket.getOutputStream();
            InputStream is = socket.getInputStream();

            System.out.println("请输入聊天信息,输入quit退出:");
            while (true) {
                String str = sc.nextLine();
                if(str.equals("quit")){
                    os.write(str.getBytes());
                    os.flush();
                    break;
                }

                os.write(str.getBytes());
                os.flush();

                byte[] bytes = new byte[1024];
                int len = is.read(bytes);
                System.out.println("反转后的信息:" + new String(bytes, 0, len));
            }
            is.close();
            os.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5、传输对象

基础类:

import java.io.Serializable;

public class Teacher implements Serializable{
    private String name;
    private int age;
    private double salary;

    public Teacher(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public double getSalary() {
        return salary;
    }

    @Override
    public String toString() {
        return "Teacher [name=" + name + ", age=" + age + ", salary=" + salary + "]";
    }
}

客户端:

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;

public class MySocket {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1", 8002);
            Scanner sc = new Scanner(System.in);
            ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream is = new ObjectInputStream(socket.getInputStream());

            System.out.println("请输入老师信息(格式:姓名-年龄-工资),输入quit结束:");

            while(true){
                String msg = sc.next();
                if(msg.equals("quit")){
                    os.writeObject(null);
                    os.flush();
                    break;
                }

                String[] parts = msg.split("-");
                if(parts.length == 3){
                    Teacher t = new Teacher(parts[0],Integer.parseInt(parts[1]), Double.parseDouble(parts[2]));
                    os.writeObject(t);
                    os.flush();
                }else{
                    System.out.println("输入格式错误");
                }
            }
            String response = (String) is.readObject();
            System.out.println("服务端回复:" + response);

            os.close();
            is.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

服务端:

import java.io.FileWriter;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class MyServerSocket {
    public static void main(String[] args) {
        int port = 8002;

        try {
            ServerSocket server = new ServerSocket(port);
            Socket socket = server.accept();
            
            ObjectInputStream is = new ObjectInputStream(socket.getInputStream());
            ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream());

            List<Teacher> teachers = new ArrayList<>();
            Teacher t;
            while((t = (Teacher)is.readObject()) != null){
                teachers.add(t);
            }
            Writer writer = new FileWriter("day30/homework/T1/teacher.txt");

            for(Teacher teacher : teachers){
                writer.write(teacher.toString());
                writer.write("\n");
            }
            os.writeObject("ok");
            writer.flush();
            writer.close();
            os.close();
            is.close();
            socket.close();
            server.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

四、UDP网络编程

java.net.DatagramSocket java.net.DatagramPacket

是UDP编程中使用到的两个类,客户端和服务器端都使用这两个类

  • java.net.DatagramSocket 负责接收和发送数据
  • java.net.DatagramPacket 负责封装要发送的数据和接收到的数据

简单写一下了解即可:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class TestSocket {
    public static void main(String[] args) {
        String ip = "127.0.0.1";
        int port = 8888;

        DatagramSocket socket = null;
        DatagramPacket packet = null;
        try {
            socket = new DatagramSocket();
            byte[] buff = "hello server".getBytes();
            packet = new DatagramPacket(buff,0,buff.length,InetAddress.getByName(ip),port);
            socket.send(packet);
            System.out.println("客户端发送成功");
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(socket != null){
                socket.close();
            }
        }
    }
}


import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class TestServerSocket {
    public static void main(String[] args) {
        byte[] buff = new byte[1024];
        int port = 8888;
        DatagramSocket socket = null;
        DatagramPacket packet = null;

        try {
            socket = new DatagramSocket(port);
            packet = new DatagramPacket(buff, 0 , buff.length);

            socket.receive(packet);
            System.out.println("客户端说:" + new String(buff, 0, packet.getLength()));

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(socket != null){
                socket.close();
            }
        }
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到