目录
网络的七层模型
应用层
表示层
会话层
传输层
网络层
数据链路层物理层
传输层协议:TCP UDP
应用层:HTTP协议
TCP/UDP区别
维度 | TCP | UDP |
---|---|---|
可靠性 | 可靠 | 不可靠 |
速度 | 稍慢 | 更快 |
通信方式 | 点对点 | 点对点、一对多、多对多 |
通信内容 | 字节码 | 数据报 |
应用场景 | 传输文件 | 聊天、视频、语音 |
三次握手和四次挥手
TCP 传输控制协议
分客户端和服务端,属于可靠协议,不会丢失数据
TCP连接需要通过三次握手机制在客户端和服务端建立起链接
三次握手
-
客户端发送信号量SYN=1 和序列号seq=J 给服务端,客户端进入SYN_SENT(信号发送状态),等待服务器回答
-
服务器收到客户端信号后,发送信号量SYN=1、ACK=1,应答值ack=J+1,新的序列号seq=K给客户端,服务器进入SYN_RCVD(收到信号)状态
-
客户端收到服务器的应答消息,发送ACK=1,和应答值ack=K+1给服务器,客户端和服务器都进入ESTABLISHED(连接建立)状态
四次挥手
客户端和服务端断开链接需要四次挥手机制断开连接
-
客户端发送信号量FIN M给服务器端,进入FIN_WAIT1状态
-
服务端收到后,返回ack M+1给客户端,进入CLOSE_WAIT状态
-
服务端在发送FIN N信号给客户端
-
客户端收到后,返回应答信号ACK=1 ack=N+1给服务端,连接关闭
socket编程
socket(套接字),用于TCP/IP协议的网络编程机制
ServerSocket 服务端 对本机的某个端口进行监听
创建
ServerSocket(int port) 参数是端口号
方法
close()关闭
Socket accept() 接受客户端连接,会堵塞线程,直到连接到客户端
Socket 客户端 代表客户端向服务端请求连接 发送网络通知
创建
Socket(String ip,int port) ip地址 端口号
方法
disconnect() 关闭
OutputStream getOutputStream() 获得输出流
InputStream getInputStream() 获得输入流
注意:IO流关闭后,socket会自动关闭
socket实现客户端与服务端对话
客户端:
package htp;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Client {
public void send(String ip, int port, String msg) {
try (Socket socket = new Socket(ip, port)) {
try (ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) {
out.writeUTF(msg);
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() throws IOException {
System.out.println("客户端启动了");
try(ServerSocket socket = new ServerSocket(8080)){
//接受消息
new Thread(()->{
while (true){
try {
Socket accept = null;
accept = socket.accept();
System.out.println("客户机连接了"+accept.getInetAddress());
ObjectInputStream input = new ObjectInputStream(accept.getInputStream());
String str = null;
System.out.println("接受到"+str);
str = input.readUTF();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
public static void main(String[] args) throws IOException {
Client client = new Client();
client.start();
client.send("192.168.1.124", 8888, "java真厉害");
}
}
服务端:
package htp;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static final int PART = 8080;
public void start() throws IOException {
System.out.println("服务器启动了");
try(ServerSocket socket = new ServerSocket(PART)){
//接受消息
new Thread(()->{
while (true){
try {
Socket accept = null;
accept = socket.accept();
System.out.println("客户机连接了"+accept.getInetAddress());
ObjectInputStream input = new ObjectInputStream(accept.getInputStream());
String str = null;
System.out.println("接受到"+str);
str = input.readUTF();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
public void send(String ip,int port,String msg){
try(Socket socket = new Socket(ip,port)){
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeUTF(msg);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
Server server = new Server();
server.start();
server.send("192.168.1.124",8888,"我是服务器");
} catch (IOException e) {
e.printStackTrace();
}
}
}
实现互相连续聊天
创建输入流线程
package htp;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
public class ReaderRunnable implements Runnable{
private Socket socket;
public ReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
while (true){
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
String s = input.readUTF();
System.out.println("接收到了"+socket.getInetAddress()+"消息:"+s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
创建输出流线程
package htp;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
public class WriterRunnable implements Runnable{
private Socket socket;
public WriterRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
Scanner scanner = new Scanner(System.in);
while (true){
try {
System.out.println("输入框:");
String msg = scanner.nextLine();
out.writeUTF(msg);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
创建服务端
package htp;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ChatHome {
public void send(String ip,int port) throws IOException {
while (true){
ExecutorService executorService = Executors.newFixedThreadPool(2);
ServerSocket socket = new ServerSocket(port);
Socket accept = socket.accept();
executorService.execute(new ReaderRunnable(accept));
executorService.execute(new WriterRunnable(accept));
}
}
public static void main(String[] args) {
try {
new ChatHome().send("192.168.1.124",8888);
} catch (IOException e) {
e.printStackTrace();
}
}
}
创建客户端
package htp;
import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ChatHome2 {
public void send(String ip,int port) throws IOException {
Socket socket = new Socket(ip,port);
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(new ReaderRunnable(socket));
executorService.execute(new WriterRunnable(socket));
}
public static void main(String[] args) {
try {
new ChatHome2().send("192.168.1.120",8080);
} catch (IOException e) {
e.printStackTrace();
}
}
}
先启动服务端,再启动客户端,就可以实现相互聊天了。
UDP编程
数据报协议,类似广播,属于不可靠的协议,无连接
服务端
DatagramSocket(int port) 指定端口获得发送的数据报
客户端
DatagramSocket() 作为客户端使用
主要方法
receive(DatagramPacket) 接收数据包
send(DatagramPacket) 发送数据报
UDP实现客户端,服务端聊天
DatagramPacket 包
DatagramPacket(String ip,int port) 发送前指定ip和端口
public class UDPServer {
public static final int PORT = 8888;
public void start(){
System.out.println("启动服务");
//创建UDP服务端
try {
DatagramSocket server = new DatagramSocket(PORT);
//接收数据报
while(true) {
byte[] buff = new byte[1024];
DatagramPacket packet = new DatagramPacket(buff,0,buff.length);
//将接收的数据放入数据报
server.receive(packet);
String msg = new String(packet.getData(),0,packet.getLength(),"UTF-8");
System.out.println("接收到:" + msg);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new UDPServer().start();
}
}
public class UDPClient {
public void send(String ip,int port,String msg){
//创建客户端
try {
DatagramSocket client = new DatagramSocket();
//创建数据报
byte[] buff = msg.getBytes();
DatagramPacket packet = new DatagramPacket(buff,0,buff.length, InetAddress.getByName(ip),port);
//发送数据报
client.send(packet);
} catch (SocketException | UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new UDPClient().send("127.0.0.1",8888,"Hello UDP!!");
}
}
可以根据socket完成udp连续聊天。
总结
网络的七层模型
TCP的三次握手和四次挥手
SOCKET编程和UDP编程