网络编程

网络编程笔记

1.1、概述

网络编程是指编写程序使不同设备(如电脑、手机)通过网络(局域网/互联网)进行数据传输、通信的技术。
核心目的:实现跨设备的数据交互,常见场景如文件传输、即时通讯、网页请求等。

1.2、网络通信的要素

实现网络通信必须具备3个核心要素:

  1. IP地址:设备在网络中的唯一标识(相当于“家庭住址”)。
  2. 端口号:设备中程序的唯一标识(相当于“家庭里的房间号”)。
  3. 通信协议:设备间数据传输的规则(相当于“交流的语言”)。

1.3、IP

  • 定义:Internet Protocol(互联网协议),是分配给网络设备的数字标签(如192.168.1.1)。
  • 分类
    • IPv4:32位二进制,格式为xxx.xxx.xxx.xxx(如127.0.0.1是本地回环地址,代表本机)。
    • IPv6:128位二进制,解决IPv4地址不足的问题(格式为8组16进制数,如2001:0db8:85a3:0000:0000:8a2e:0370:7334)。
  • 常用命令
    • Windows:ipconfig(查看本机IP)。
    • Linux/macOS:ifconfigip addr

1.4、端口

  • 定义:设备中程序的唯一编号(范围:0~65535),用于区分同一设备上的不同应用。
  • 分类
    • 知名端口(0~1023):系统/常用服务占用(如HTTP的80端口、HTTPS的443端口)。
    • 动态端口(1024~65535):普通程序可使用的端口(编程时建议用1024之后的端口,避免冲突)。
  • 注意:同一设备上,一个端口同一时间只能被一个程序占用。

1.5、通信协议

  • 定义:设备间数据传输的规则、格式约定,确保双方能“读懂”对方的数据。
  • 常见协议
    1. TCP:可靠的、面向连接的协议(如文件传输、HTTP请求),传输前需建立“三次握手”,传输后需“四次挥手”断开连接。
    2. UDP:不可靠的、无连接的协议(如即时通讯、视频通话),速度快但可能丢包。
    3. HTTP/HTTPS:应用层协议,基于TCP,用于网页数据传输(HTTPS是加密的HTTP)。

1.6、TCP

  • 核心特点:可靠、面向连接、传输效率略低。

  • 连接建立:三次握手(像打电话确认对方能听到)
    通俗流程:

    1. 客户端→服务端:“喂,你能听到吗?”(发送SYN包,请求建立连接)
    2. 服务端→客户端:“能听到,你能听到我吗?”(回复SYN+ACK包,确认请求+请求自己的连接)
    3. 客户端→服务端:“能听到,那咱开始聊吧!”(回复ACK包,确认对方的连接)
      公式标记:SYN → SYN+ACK → ACK
      作用:确保双方“收发能力都正常”,避免无效连接。
  • 连接断开:四次挥手(像挂电话前确认对方说完了)
    通俗流程:

    1. 客户端→服务端:“我说完了,准备挂了”(发送FIN包,请求断开)
    2. 服务端→客户端:“好的,我知道了”(回复ACK包,确认请求)
    3. 服务端→客户端:“我也说完了,你可以挂了”(发送FIN包,自己的内容发完了)
    4. 客户端→服务端:“收到,那我挂了”(回复ACK包,确认断开)
      公式标记:FIN → ACK → FIN → ACK
      作用:确保双方“数据都发完了”,避免丢数据。
  • 典型场景:文件上传
    流程:

    1. 客户端通过IP+端口连接服务端(三次握手建立连接)。

    2. 客户端读取本地文件,通过输出流将文件数据发送给服务端。

    3. 服务端通过输入流接收数据,用文件输出流保存到本地。

    4. 传输完成后,双方通过“四次挥手”断开连接。


      客户端向服务端传输文件示例

客户端代码
package com.thomas.lesson02;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class TcpClientDemo01 {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream outputStream = null;
        try {
            //1.要知道服务器的地址端口号
            InetAddress serverIP = InetAddress.getByName("127.0.0.1");
            int serverPort = 9999;
            //2.创建一个socket连接
            socket = new Socket(serverIP,serverPort);
            //3.发送信息,IO流
             outputStream = socket.getOutputStream();
            if (outputStream != null) {
                outputStream.write("你好".getBytes());
            }else {
                System.out.println("连接失败,输出流为空");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
服务端
package com.thomas.lesson02;

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

public class TcpServerDemo01 {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream inputStream = null;
        ByteArrayOutputStream baos = null;
        try {
            //1.有一个地址
                serverSocket = new ServerSocket(9999);
                //2.等待客户链接过来
                socket = serverSocket.accept();
                //3.读取客户端的信息
                inputStream = socket.getInputStream();
                //管道流
                baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len;
                while ((len = inputStream.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
                System.out.println(baos.toString());
        } catch (IOException e) {
                e.printStackTrace();
            }finally {
            if (baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {}
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务端向客户端发送传输完毕信息

部分不重叠代码-客户端
	//通知服务器传输完毕
	socket.shutdownOutput();
	//确定服务器接收完毕
	InputStream is = socket.getInputStream();
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	byte[] b2 = new byte[1024];
	int len2;
	while ((len2=is.read(b2))!=-1) {
    	baos.write(b2,0,len2);
	}
	String receivedMsg = baos.toString();
	System.out.println(receivedMsg);
服务端
	//告诉客户端发送完毕
	outputStream = socket.getOutputStream();
	outputStream.write("ok,收到".getBytes());

用DataOutputStream的writeUTF方法传输字符串与转为字节的相比

客户端
package com.thomas.test;

import java.io.*;
import java.net.Socket;
/*
* 千万千万记得关闭资源
*/
public class TcpClient {
    public static void main(String[] args) throws IOException {
        //建立socket
        Socket socket = new Socket("127.0.0.1",8080);
        //输出流,作为发送方,建立输出管道
        OutputStream outputStream = socket.getOutputStream();
        //输入流,从本地获取文件
        FileInputStream fis = new FileInputStream("day02.md");
        //输出文件
        int len;
        //字节型数组缓冲区
        byte[] b = new byte[1024];
        while ((len=fis.read(b))!=-1) {
            //输出流写文件
            outputStream.write(b,0,len);
        }
        socket.shutdownOutput();
        fis.close();
        //使用readUTF方法读取
        DataInputStream dis = new DataInputStream(socket.getInputStream());
        //创建字符串对象存储读取字符串
        String str = dis.readUTF();
        System.out.println(str);
        dis.close();
        outputStream.close();
        socket.close();
    }
}

1.7、UDP

发送短信,不需要连接


发送消息

发送端
package com.thomas.lesson03;

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

public class UdpClientDemo01 {
    public static void main(String[] args) throws IOException {
        //1.建立socket
        DatagramSocket socket = new DatagramSocket();
        //2.建立包
        String msg = "你好,服务器";
        //发送给谁
        InetAddress address = InetAddress.getByName("127.0.0.1");
        int port = 9090;
        DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0,msg.getBytes().length,address,port);
        //3.发送包
        socket.send(packet);
        //4.关闭流
        socket.close();
    }
}
接收端
package com.thomas.lesson03;

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

public class UdpServerDemo01 {
    public static void main(String[] args) throws Exception {
        //socket
        DatagramSocket socket = new DatagramSocket(9090);
        //接收包
        byte[] buf = new byte[1024];
        //packet
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        socket.receive(packet);
        System.out.println(new String(packet.getData(),0,packet.getLength()));
        //关流
        socket.close();
    }
}
posted @ 2025-12-20 21:20  coldmist  阅读(0)  评论(0)    收藏  举报