java网络通讯

网络编程

概述

将不同物理设备通过通讯线路连接起来,在网络系统的作用下实现通讯和内容共享。

网络通讯的要素

  1. 网路编程中的两个问题
    • 如何准确定位一台主机或多台主机
    • 找到主机之后怎么进行通讯
  2. 网路编程的要素
    • IP + 端口号
    • 网络通讯协议

网络编程主要针对--传输层。

IP

java 复制代码
public class TestInetAddress {

    public static void main(String[] args) {
        // InetAddress 没有构造方法
        try {
            InetAddress inetAddress1 = InetAddress.getByName("www.baidu.com");
            System.out.println(inetAddress1);

            //查询本机地址
            InetAddress inetAddress2 = InetAddress.getByName("127.0.0.1");
            System.out.println(inetAddress2);
            InetAddress inetAddress3 = InetAddress.getByName("localhost");
            System.out.println(inetAddress3);

            //常用方法
            System.out.println(inetAddress2.getCanonicalHostName());
            System.out.println(inetAddress2.getHostAddress());
            System.out.println(inetAddress2.getHostName());
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
    }
}

端口

端口表示一台计算机上的某一个进程。

  • 不同进程的端口号不同,端口号用来区分不同的软件!

  • 端口的范围:0~65535

  • TCP和UDP的端口号范围都是0~65535;单个协议下端口不能冲突,TCP和UDP在同一台计算机上都拥有80端口这个不会冲突;

  • 端口分类:

    • 公有端口:0~1023
      • HTTP:80
      • HTTPS:43
      • FTP:21
      • Telnet:23
    • 程序端口:1024~49151,分配用户或者程序
      • Tomcat:8080
      • MySQL:3306
      • Oracle:1521
    • 动态、私有端口:49152~65535
    cmd 复制代码
    netstat -ano #查看所有的端口
    netstat -ano|findstr "5900" #查看指定的端口
    tasklist|findstr "8696" #查看指定端口的进程
    java 复制代码
    public class TestInetSocketAddress {
    
        public static void main(String[] args) {
            //根据IP+port获取主机信息
            InetSocketAddress inetSocketAddress1 = new InetSocketAddress("127.0.0.1", 8080);
            InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost", 8080);
    
            System.out.println(inetSocketAddress1);
            System.out.println(inetSocketAddress2);
    
            System.out.println(inetSocketAddress1.getAddress());//获取地址
            System.out.println(inetSocketAddress1.getHostName());//获取主机名
            System.out.println(inetSocketAddress1.getPort());//获取端口
        }
    }

通讯协议

按照约定的通讯格式(json、xml等格式)、同步方式进行通讯。比如:两个不同地区的人用普通话进行加交流,而不是各自用方言。

TCP/IP协议:是一组协议

三次握手和四次挥手,核心就是:TCP协议像两个礼貌且严谨的人沟通,建立连接时要双向确认,断开连接时也要双向确认,确保没有信息遗漏或误操作。

  • 三次握手
java 复制代码
1.你拨通电话说:"喂,听得到吗?"(第一次握手:客户端发送连接请求)
2.朋友接起电话回答:"听得到,你呢?"(第二次握手:服务端确认收到请求,并也发出连接请求)
3.你接着说:"我也听得到,我们开始聊吧。"(第三次握手:客户端确认服务端的请求)
至此,双方都确认了对方能听清自己,自己也能听清对方,可靠的通话(连接)就建立了。

客户端A和服务端B建立连接时:A先请求B开始建立连接;B收到请求后应答A表示已收到A的请求;A在收到B的请求后再次应答B,表示A在等待B的应答并正式建立通讯。

  • 四次挥手
java 复制代码
四次挥手,就像挂电话结束通话:
1.你说:"我要说的都说完了,我准备挂电话了。"(第一次挥手:客户端发送断开请求)
2.朋友说:"好的,我知道了。"(但朋友可能还有话没说完,所以他先确认收到你的挂断意向,但不立即挂断)(第二次挥手:服务端确认断开请求)
3.朋友把最后几句话说完,然后说:"我也说完了,我也要挂了。"(第三次挥手:服务端发送自己的断开请求)
4.你回答:"好的,再见。"(第四次挥手:客户端确认服务端的断开请求)
至此,双方都确认了对方已无话要说,且都知道通话要结束,才能安心挂断(连接关闭)。

之所以挥手是四次,客户端A在告知服务端B断开连接时,B应答A可以断开(表示B收到A的断开请求);此时B检查自己要传输给A的内容是否完成,完成后通知A断开连接;A在收到B的正式断开通知后,回复B表示内容已全部收到可以断开。

TCP和UDP

TCP--用户传输协议,比如:打电话

  • 需要建立连接,才能通讯;
  • 相对于UDP传输可靠,效率低;
  • 面向字节流,传输的内容可以分开传输,接收后组合起来;
  • 适用场景:数据库连接访问、网页浏览、文件传输、远程登录、电子邮件等;

UDP--用户数据报协议,比如:发短信

  • 不需要建立连接就能通讯;
  • 相对于TCP传输不可靠,效率高;
  • 面向数据报,传输内容不能分开,一次传输一数据个报;
  • 使用场景:实时音视频、广播等。
TCP
  • 服务端

​ 1.建立服务,监听指定的端口

​ 2.等待客户端连接

​ 3.接受客户端消息

java 复制代码
public class TCPServerDemo01 {


    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket accept = null;
        InputStream is = null;
        ByteArrayOutputStream bos = null;
        try {
            //1.建立服务
            serverSocket = new ServerSocket(9999);
            //2.等待请求
            accept = serverSocket.accept();
            //3.接受请求
            is = accept.getInputStream();
            //建立管道流接收请求
            bos = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            int len = 0;
            while((len = is.read(buf)) != -1){
                bos.write(buf,0,len);
            }
            System.out.println(bos.toString());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if(bos != null){
                try {
                    bos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            if(accept != null){
                try {
                    accept.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            if(serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}
java 复制代码
//在处理客户端消息时,以下处理会存在问题:如果缓冲区大小1024字节正好截断了一个多字节字符(如UTF-8的中文字符);最后一个字符可能被分割,导致乱码;所以使用"管道流"进行处理
byte[] buf = new byte[1024];
int len = 0;
StringBuffer sb = new StringBuffer();
while((len = is.read(buf)) != -1){
    String msg = new String(buf,0,len);
    sb.append(msg);
}
System.out.println(sb.toString());
  • 客户端

    1.连接服务

​ 2.发送消息

java 复制代码
public class TCPClientDemo01 {

    public static void main(String[] args) {
        Socket socket = null;
        OutputStream os = null;
        try {
            //1.获取连接
            InetAddress serIp = InetAddress.getByName("127.0.0.1");
            int port = 9999;
            socket = new Socket(serIp, port);
            //2.发送请求
            byte[] bytes = "客户端发送测试".getBytes();
            os = socket.getOutputStream();
            os.write(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if(os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }


    }
}

使用TCP连接,实现文件传输

客户端:

java 复制代码
public static void main(String[] args) {
    Socket socket = null;
    OutputStream os = null;
    FileInputStream fis = null;
    InputStream is = null;
    ByteArrayOutputStream bos = null;
    try {
        //1.和服务器建立连接
        socket = new Socket(InetAddress.getByName("127.0.0.1"),8888);
        //2.读取要上上传的文件
        os = socket.getOutputStream();
        fis = new FileInputStream(new File("1.png"));
        //3.发送给服务端
        byte[] buf = new byte[1024];
        int len = 0;
        while((len = fis.read(buf)) != -1){
            os.write(buf,0,len);
        }
        System.out.println("客户端发送文件结束");
        socket.shutdownOutput();//表示文件传输完成

        is = socket.getInputStream();
        bos = new ByteArrayOutputStream();
        byte[] buf2 = new byte[1024];
        int len2 = 0;
        while((len2 = is.read(buf2)) != -1){
            bos.write(buf2,0,len2);
        }
        System.out.println("客户端接收到的返回:"+bos.toString());
    } catch (IOException e) {
        throw new RuntimeException(e);
    }finally {
        try {
            if(bos != null){
                bos.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        try {
            if(fis != null){
                fis.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        try {
            if(os != null){
                os.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        try {
            if(socket != null){
                socket.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

服务端:

java 复制代码
public static void main(String[] args) {
    ServerSocket serverSocket = null;
    Socket socket = null;
    InputStream is = null;
    FileOutputStream fos = null;
    OutputStream os = null;
    try {
        //1.启动服务,监听指定端口
        serverSocket = new ServerSocket(8888);
        System.out.println("服务端监听中。。。");
        socket = serverSocket.accept();
        //2.读取接收的文件
        is = socket.getInputStream();
        fos = new FileOutputStream(new File("receive.png"));
        byte[] buf = new byte[1024];
        int len = 0;
        while((len = is.read(buf)) != -1){
            fos.write(buf,0,len);
        }
        System.out.println("服务端文件接收成功");

        //发送消息通知客户端文件接收成功
        os = socket.getOutputStream();
        os.write("服务端接收文件成功,可以断开连接".getBytes());
    } catch (IOException e) {
        throw new RuntimeException(e);
    } finally {
        try {
            if(os != null){
                os.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        try {
            if(fos != null){
                fos.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        try {
            if(is != null){
                is.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        try {
            if(socket != null){
                socket.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try {
            if(serverSocket != null){
                serverSocket.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
UDP

代码示例

注意:UDP通讯时,会以包的形式发送和接收信息;在接收消息时需根据实际情况定义接收端的byte大小,防止接收打的消息丢失。

发送端

java 复制代码
public class UPDClientTest01 {

    public static void main(String[] args) {

        DatagramSocket socket = null;
        try {
            //1.建立socket
            socket = new DatagramSocket();
            //2.创建要发送的包
            String reqMsg = "UDP";
            InetAddress ip = InetAddress.getByName("127.0.0.1");
            int port = 9999;
            DatagramPacket sendPacket = new DatagramPacket(reqMsg.getBytes(), 0, reqMsg.getBytes().length, ip, port);
            //3.发送
            socket.send(sendPacket);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //4.关闭流
            if(socket != null){
                socket.close();
            }
        }
    }
}

接收端

java 复制代码
public class UPDReceiveTest01 {

    public static void main(String[] args) {
        DatagramSocket socket = null;
        try {
            //1.启动socket监听
            socket = new DatagramSocket(9999);
            //2.接收包
            byte[] buf = new byte[1024];//如果接收到的消息大于这个长度,超出部分会被丢弃,需要根据实际情况进行定义
            DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
            socket.receive(packet);
            System.out.println(packet.getAddress());//发送端的IP
            System.out.println(new String(packet.getData(),0, packet.getLength()));//接收到的消息
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //3.关闭连接
            if(socket != null){
                socket.close();
            }
        }
    }
}
UDP--实现聊天
java 复制代码
public class UdpSendDemo01 {
    public static void main(String[] args) throws Exception{
        System.out.println("发送端");
        DatagramSocket socket = new DatagramSocket(6666);

        while(true){
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String reqMsg = reader.readLine();
            DatagramPacket packet = new DatagramPacket(reqMsg.getBytes(), 0, reqMsg.getBytes().length, InetAddress.getByName("127.0.0.1"), 8888);
            socket.send(packet);

            if(reqMsg.indexOf("bye") != -1){
                break;
            }
        }
        socket.close();

    }
}
java 复制代码
public class UdpSendDemo02 {

    public static void main(String[] args) throws Exception{
        System.out.println("接收端");
        DatagramSocket socket = new DatagramSocket(8888);
        while(true){
            byte[] buf = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
            socket.receive(packet);
            byte[] data = packet.getData();
            String reqMsg = new String(data,0, packet.getLength());
            System.out.println(reqMsg);
            if(reqMsg.indexOf("bye") != -1){
                break;
            }
        }
        socket.close();
    }
}
UDP--在线聊天
java 复制代码
public class ChatSend implements Runnable{

    private String targetIp;//接收方IP
    private int targetPort;//接收方端口
    private DatagramSocket socket = null;

    public ChatSend(String targetIp,int targetPort) throws IOException{
        this.targetIp = targetIp;
        this.targetPort = targetPort;
        socket = new DatagramSocket();
    }

    @Override
    public void run() {
        while(true){
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                String reqMsg = reader.readLine();
                DatagramPacket packet = new DatagramPacket(reqMsg.getBytes(), 0, reqMsg.getBytes().length, InetAddress.getByName(this.targetIp), this.targetPort);
                socket.send(packet);
                if(reqMsg.indexOf("bye") != -1){
                    break;
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        socket.close();
    }
}
java 复制代码
public class ChatReceive implements Runnable{

    private int myPort;//监听的端口号
    private String name;//发送者名称
    private DatagramSocket socket = null;

    public ChatReceive(int myPort, String name) throws IOException{
        this.myPort = myPort;
        this.name = name;
        socket = new DatagramSocket(myPort);
    }

    @Override
    public void run() {
        while(true){
            try {
                byte[]  buf = new byte[1024];
                DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
                socket.receive(packet);

                String msg = new String(packet.getData(), 0, packet.getLength());
                System.out.println(name+":"+msg);

                if(msg.indexOf("bye") != -1){
                    break;
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        socket.close();
    }
}
java 复制代码
public class ChatDemo01 {

    public static void main(String[] args) throws IOException {
        System.out.println("学生");
        new Thread(new ChatSend("127.0.0.1",8888)).start();
        new Thread(new ChatReceive(6666,"老师")).start();
    }
}
java 复制代码
public class ChatDemo02 {
    public static void main(String[] args) throws IOException {
        System.out.println("老师");
        new Thread(new ChatSend("127.0.0.1",6666)).start();
        new Thread(new ChatReceive(8888,"学生")).start();
    }
}

URL下载网络资源

java 复制代码
public class URLDemo01 {

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://localhost:8080/helloworld/index.jsp?username=zhangsan&password=123");
        System.out.println(url.getProtocol());//协议
        System.out.println(url.getHost());//主机IP
        System.out.println(url.getPort());//端口
        System.out.println(url.getFile());//全路径
        System.out.println(url.getPath());//文件
        System.out.println(url.getQuery());//参数
    }
}

URL下载网络资源代码

java 复制代码
public class URLDownload {

    public static void main(String[] args) {
        HttpURLConnection connection = null;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            //获取URL对象
            URL url = new URL("https://gips1.baidu.com/it/u=1410005327,4082018016&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280");
            //获取连接
            connection = (HttpURLConnection)url.openConnection();
            //获取输入流
            is = connection.getInputStream();
            byte[] buf = new byte[1024];
            int len = 0;
            fos = new FileOutputStream(new File("cat.png"));
            while((len = is.read(buf)) != -1){
                fos.write(buf,0,len);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            if(connection != null){
                connection.disconnect();//断开连接
            }
        }
    }
}
相关推荐
罗技1231 小时前
告别“兼容模式“:Easysearch 有了自己的官方 Python 客户端
开发语言·python
NE_STOP1 小时前
Redis--集群搭建与主从复制原理
java
IT策士1 小时前
Python 常见的设计模型:入门到精通
开发语言·python
好奇的菜鸟1 小时前
Java开发常用中间件,Docker安装。
java·docker·中间件
许泽宇的技术分享1 小时前
别再把 AI Agent 当“会聊天的脚本”:Hermes Agent 源码级拆解(架构、框架、实战、趋势,一文吃透)
java·linux·网络
不会写DN1 小时前
如何通过 Python 实现招聘平台自动投递
开发语言·前端·python
lbb 小魔仙1 小时前
Ollama + Python 本地大模型部署与API调用:从零开始搭建私有AI助手
开发语言·人工智能·python
邪修king2 小时前
C++ typename & auto 彻底讲透:核心作用、推导规则、避坑指南
开发语言·c++
会编程的土豆2 小时前
MySQL 多表查询
开发语言·数据库·python·mysql