Java 基础查漏补缺【网络篇】

Posted by 石福鹏 on 2017-05-12

网络基础

通讯协议的分层思想

由于节点之间联系很复杂,在制定协议的时候,把复杂成份分解成一些简单的成分,再将它们复合起来。

最常用的复合方式就是层次方式,即同层之间可以通信、上一层可以调用下一层,而与再下一层不发生关系,隔各层互不影响,利于系统的开发和扩展。

image-20201108152947585

image-20201014173820770

image-20201014173829692

IP协议(推荐书籍:《TCP/IP详解》)

对我们最大的贡献,就是提供了独一无二的IP地址

是网际层的主要协议,支持网间互联的数据报通讯,提供的主要功能有:

  • 无连接数据报传送
  • 数据报路由选择和差错控制

TCP协议和UDP协议

TCP. (可靠的,效率低)

是专门设计用于在不可靠的因特网上提供 可靠的 、端对端的字节流通信的协议。他是异种骨面对连接的协议,TCP连接是字节流而非报文流

UDP(不可靠的,发出去对方收不收到,不关注、效率高)

游戏间的数据传输属于UDP

UDP向应用程序提供了一种发送封装的原始IP数据报的方法、并且发送时无需建立连接。是一种不可靠的连接

Socket

  • 两个Java应用程序可通过一个双向的网络通讯连接实现数据交换,这个双向链路的一端成为一个Socket

  • Socket 通常用来实现client~server连接

  • java.net 包中定义了两个类SocketServerSocket,分别用来实现双向连接的ClientServer

  • 建立连接时所需的寻址信息为远程计算机的IP地址和端口号(端口号是为了区分同一台机器上不同的应用程序)

端口号又分为TCP端口、UDP端口,每台机器有65536个TCP端口,65536个UDP端口

服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TCPServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(6666);
while (true) {
Socket s = serverSocket.accept(); //阻塞式
System.out.println("A socket Accept");
DataInputStream dis = new DataInputStream(s.getInputStream());
System.out.println(dis.readUTF());
dis.close();
s.close();
}
}
}

客户端:

1
2
3
4
5
6
7
8
9
10
public class TCPClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 6666);
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF("hello server");
dos.flush();
dos.close();
}
}

当然,这个是可以用异步实现的,这里只做知识说明

image-20201109072532526

UDP网络编程

1
2
3
4
5
6
7
8
9
10
11
public class TestUDPServer {
public static void main(String[] args) throws Exception {
byte buf[] = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
DatagramSocket ds = new DatagramSocket(3456);
while (true) {
ds.receive(dp);
System.out.printf(new String(buf,0,dp.getLength()));
}
}
}

1
2
3
4
5
6
7
8
9
public class TestUDPClient {
public static void main(String[] args) throws Exception {
byte[] b = "Hello".getBytes();
DatagramPacket dp = new DatagramPacket(b, b.length, new InetSocketAddress("127.0.0.1", 3456)); //向3456发送数据包
DatagramSocket ds = new DatagramSocket(9999); //client占据9999 端口
ds.send(dp);
ds.close();
}
}

例子:将一个Long类型的数据写入数据包

image-20201109080832667

image-20201109081222090