TCP和“三次握手”
TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。第一次握手客户端向服务器端发出连接请求,等待服务器确认,第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求,第三次握手,客户端再次向服务器端发送确认信息,确认连接。
由于TCP协议的面向连接特性,它可以保证传输数据的安全性,所以是一个被广泛采用的协议,例如在下载文件时,如果数据接收不完整,将会导致文件数据丢失而不能被打开,因此,下载文件时必须采用TCP协议,传输时不限制大小。
TCP套接字
ServerSocket类设计成“监听器”,等待客户端连接的到来。因此,ServerSocket用于服务器。
Socket类用于客户端,它被设计成连接服务器套接字并且初始化协议的交换。
客户端代码:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/*
* 客户端连接服务器步骤
* (1) 创建Socket
* (2) 打开连接到Socket的输入/输出流
* (3) 按照一定协议对Socket执行读写操作
* (4) 关闭Socket
*/
public class TestClient {
public static void main(String[] args) throws IOException {
// 创建客户端套接字对象
// 发起与服务端的请求 服务端IP和端口号
Socket socket = new Socket("localhost", 8899);
// 向服务端发送数据
// 连接到从套接字对象获取的字节输出流
OutputStream os = socket.getOutputStream();
// 通过字节输出流 写数据
os.write("你好,我来客户端".getBytes());
// 从服务端接收数据
// 连接到从套接字对象获取的字节输入流
InputStream is = socket.getInputStream();
// 创建缓冲区
byte[] bs = new byte[1024];
// 通过字节输入流 读数据
// 读到数据返回字节长度 返回-1
int len = is.read(bs);
if (len == -1) {
System.out.println("从服务端读取信息失败");
} else {
// 打印接收到的信息
System.out.println(new String(bs, 0, len));
}
// 关流
socket.close();
}
}
服务端代码:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
* 服务器接收客户端请求步骤
* (1) 创建一个ServerSocket实例,监听客户端发来的请求。
* (2) 与客户端获取连接后,创建一个Socket实例
* (3) 利用I/O流与客户端进行通信
* (4) 关闭Socket
*/
public class TestServer {
public static void main(String[] args) throws IOException {
// 创建服务端对象 监听客户端发来的请求
ServerSocket ss = new ServerSocket(8899);
// 如果请求连接成功 返回客户端的socket 如果没有客户端连接 会阻塞
Socket socket = ss.accept();
// 获取客户端对应socket的字节输入流
InputStream is = socket.getInputStream();
// 创建缓冲区
byte[] bs = new byte[1024];
// 通过字节输入流读取数据 返回字节长度 读不到返回-1
int len = is.read(bs);
if (len == -1) {
System.out.println("从客户端读取信息失败");
} else {
// 打印接收到的信息
System.out.println(new String(bs, 0, len));
}
// 向客户端发送信息
OutputStream os = socket.getOutputStream();
// 通过字节输出流输出数据
os.write("你好,我来自服务器".getBytes());
// 关流
ss.close();
}
}