你问我互联网工程设计学了啥?emm。。。感觉上课都在照着抄代码,要说什么印象特别深,脑海里还真没剩啥了。
文章目录
网络通讯
IP
定位某台计算机
端口号
定位某个应用程序
客户端和服务端
发起请求端为客户端,发送响应端为服务端
TCP与UDP
什么是网络模型
4层,应用层(HTTP协议),传输层(TCP,UDP协议),网络层(IP协议),链路层(以太网协议)
任何计算机语言通讯,底层都使用socket技术
为什么socket支持这么多语言?
socket遵循一个二进制的端口号+IP的规范进行传输,所以可以跨语言使用。
socket核心协议:TCP和UDP
TCP和UDP的区别
UDP面向无连接 — 即不建立连接、限制传输64k的不可靠协议
TCP面向连接协议,三次握手后进行通讯,通过字节流进行传输,效率比UDP低,但比UDP靠谱。
什么是三次握手
当三次握手成功之后,才开始进行数据传输。
第一次握手:客户端:发送报文给服务端,SYN=J
第二次握手:服务端:发送报文给客户端,ACK=J+1,SYN=K
第三次握手:客户端:发送报文给服务端,ACK=K+1
什么是四次挥手
结束通信会进行四次挥手。
第一次挥手:客户端:发送FIN=M
第二次挥手:服务端:发送SYN=M+1
第三次挥手:服务端:发送FIN=N
第四次挥手:客户端:发送ACK=N+1
为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的 LISTEN 状态下的 SOCKET 当收到 SYN 报文的建连请求后,它可以把 ACK 和 SYN(ACK 起应答作用,而 SYN 起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的 FIN 报文通知时,它仅仅表示对方没有数据发送给你了,但是你还可以给对方发送数据,也有这么种可能,你还有一些数据在传给对方的途中,所以你不能立马关闭连接,也即你可能还需要把在传输途中的数据给对方之后,又或者,你还有一些数据需要传输给对方后,(再关闭连接)再发送FIN 报文给对方来表示你同意现在可以关闭连接了,所以它这里的 ACK 报文和 FIN 报文多数情况下都是分开发送的。
UDP的客户端与服务端通讯例子
UDP核心是DatagramSocket和DatagramPacket。
服务端,用DatagramSocket+传入端口创建服务器,并且建立DatagramPacket来接收客户端的数据包
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* udp服务器
*
* @author uuz
* @date 2021/01/11
*/
public class UdpServer {
/**
* 端口号
*/
static int PORT = 9009;
/**
* 缓冲区大小
*/
static int BUFFER_SIZE = 1024;
/**
* 正在运行
*/
static boolean IS_RUNNING = true;
public static void main(String[] args) throws IOException {
System.out.println("UDP SERVER IS RUNNING...");
// 创建服务器端口号,默认使用本机ip
DatagramSocket datagramSocket = new DatagramSocket(PORT);
while (IS_RUNNING) {
// 定义数据包
byte[] buf = new byte[BUFFER_SIZE];
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
// 接收客户端发来的数据,将数据封装给数据包,此方法阻塞接收
datagramSocket.receive(datagramPacket);
// 打印来源地址
System.out.printf("来源IP地址: %s:%s\n内容: %s\n",
datagramPacket.getAddress(),
datagramPacket.getPort(),
new String(datagramPacket.getData(), 0, datagramPacket.getLength()));
}
}
}
客户端,构造DatagramPacket,传入服务器IP和端口,使用datagramSocket发送
import java.io.IOException;
import java.net.*;
public class UdpClient {
static String REMOTE_ADDRESS = "127.0.0.1";
public static void main(String[] args) throws IOException {
System.out.println("新建Socket客户端");
// 创建一个socket客户端
DatagramSocket datagramSocket = new DatagramSocket();
// 要发送的内容
String content = "这是一条测试信息";
// 转换成byte[]
byte[] bytes = content.getBytes();
// 创建数据包,带上要的发送IP和端口
DatagramPacket dp = new DatagramPacket(bytes,
bytes.length,
InetAddress.getByName(REMOTE_ADDRESS),
UdpServer.PORT);
datagramSocket.send(dp);
datagramSocket.close();
System.out.println("发送UDP结束");
}
}
TCP的客户端和服务端
服务器端
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* tcp服务器
*
* @author uuz
* @date 2021/01/11
*/
public class TCPServer {
static int PORT = 8889;
static int BUFFER_SIZE = 1024;
static boolean isRunning = true;
public static void main(String[] args) throws IOException {
System.out.println("TCP SERVER START");
// 创建服务器端口号
ServerSocket serverSocket = new ServerSocket(PORT);
while (isRunning) {
// 阻塞接收信息
Socket socket = serverSocket.accept();
// 获取socket传输的字节流
InputStream inputStream = socket.getInputStream();
// 将字节流转为String
byte[] bytes = new byte[BUFFER_SIZE];
int length = inputStream.read(bytes);
// 转换成String
String data = new String(bytes, 0, length);
// 打印输出
System.out.println(data);
}
serverSocket.close();
}
}
客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
static String REMOTE_ADDRESS = "127.0.0.1";
public static void main(String[] args) throws IOException {
System.out.println("tcp 客户端");
// 连接服务器
Socket socket = new Socket(REMOTE_ADDRESS, TCPServer.PORT);
// 获取字节流
OutputStream outputStream = socket.getOutputStream();
// 发送
outputStream.write("这是一条测试".getBytes());
// 关闭连接
socket.close();
}
}
服务端多线程版
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* tcp服务器
*
* @author uuz
* @date 2021/01/11
*/
public class TCPServer {
static int PORT = 8889;
static int BUFFER_SIZE = 1024;
static int THREAD_POOL_SIZE = 10;
static boolean isRunning = true;
public static void main(String[] args) throws IOException {
System.out.println("TCP SERVER START");
// 创建服务器端口号
ServerSocket serverSocket = new ServerSocket(PORT);
// 创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
while (isRunning) {
// 阻塞接收信息
Socket socket = serverSocket.accept();
executorService.execute(new Runnable() {
@SneakyThrows
@Override
public void run() {
// 获取socket传输的字节流
InputStream inputStream = socket.getInputStream();
// 将字节流转为String
byte[] bytes = new byte[BUFFER_SIZE];
int length = inputStream.read(bytes);
// 转换成String
String data = new String(bytes, 0, length);
// 打印输出
System.out.println(data);
}
});
}
serverSocket.close();
}
}