Java网络编程

简介

通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。

网络模型


网络编程三要素

  • IP地址

    • 给定一个IP地址,能唯一确定一台网络上的计算机

    • 127.0.0.1 代表本机地址

    • IP地址的分类:

      IPV4: 4个字节组成, 32bit, 每个字节0-255, 能表示42亿个IP地址.

      IPV6: 8个无符号的整数组成, 128bit

  • 端口号

    • 表示计算上的一个程序的进程.
    • 不同的进程有着不同的端口号. 用来区分软件.
    • 0 - 65535
    • TCP, UDP的端口号的独立的, 但是单个协议下,端口号不能冲突.
    • 公有端口号: 0 - 1023
    • 分配给用户/程序使用的端口: 1024 - 49151
    netstat -ano  //查看所有的端口
    netstat -ano|findstr "8080" //查看指定的端口
    tasklist|findstr "8080" //查看指定端口进程
    
  • 通讯协议

    • TCP: 安全可靠的协议, 先要创建连接, 才能进行接下来的交互

    • TCP三次握手: A(客户端) B(服务端), 形象记忆如下:

      A: 你瞅啥?

      B: 瞅你咋地?

      A: 来打一架.

      客户端先确认与服务端进行连接确认, 需要进行三次握手.

      第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

      第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

      第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

    • TCP四次挥手:

      A: 我要断开连接了

      B: 你确定要断开连接了吗

      B: 你真的要断开连接了吗

      A: 是的

      四次挥手确认断开链接.

      1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
      2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
      3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
      4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
      5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
      6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。


TCP编程

package com.smile.test.socket;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;

public class GreetingServer extends Thread{
    private ServerSocket serverSocket;
    public GreetingServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
        serverSocket.setSoTimeout(100000);
    }
    public void run(){
        while(true){
            try{
                Socket socket = serverSocket.accept();
                InputStream inputStream = socket.getInputStream();
                DataInputStream dataInputStream = new DataInputStream(inputStream);
                DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
                dataOutputStream.writeUTF("thank you for you connection" + socket.getLocalSocketAddress());
                socket.close();
            }catch (SocketTimeoutException e) {
                System.out.println("socket timeout");
                break;
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        int port = 6066;
        try{
            Thread t = new GreetingServer(port);
            t.run();
        }catch (IOException e) {
            e.printStackTrace();
        }
        }
}

package com.smile.test.socket;

import java.io.*;
import java.net.Socket;

public class SocketTest {

    public static void main(String[] args){
        String serverName = "localhost";
        int port = 6066;
        try {
            System.out.println("连接到" + serverName + "端口号" + port);
            Socket client = new Socket(serverName, port);
            System.out.println("远程主机地址:" + client.getRemoteSocketAddress());
            OutputStream outputStream = client.getOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            dataOutputStream.writeUTF("hello from" + client.getLocalSocketAddress());
            InputStream inputStream = client.getInputStream();
            DataInputStream dataInputStream = new DataInputStream(inputStream);
            System.out.println("服务器响应" + dataInputStream.readUTF());
            client.close();
        }catch (IOException e){
            e.printStackTrace();
        }

    }
}

UDP编程

package com.smile.test.socket;

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

public class UDPClient {
    public static void main(String[] args) throws IOException {
        InetAddress localHost = InetAddress.getByName("localhost");
        DatagramSocket datagramSocket = new DatagramSocket();
        String msg = "hello";
        DatagramPacket datagramPacket = new DatagramPacket(msg.getBytes(),msg.length(),localHost,9000);
        datagramSocket.send(datagramPacket);
        datagramSocket.close();
    }
}
package com.smile.test.socket;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPServer {
    public static void main(String[] args) throws IOException {
        DatagramSocket socket = new DatagramSocket(9000);
        byte[] buff = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buff, buff.length);
        socket.receive(packet);
        System.out.println(new String(packet.getData(),0, packet.getLength()));
        socket.close();
    }
}

参考博客:
https://www.cnblogs.com/bj-mr-li/p/11106390.html
https://blog.csdn.net/qq_41923622/article/details/85805003

原文地址:https://www.cnblogs.com/lvzl/p/14664727.html