一、TCP定义
面向连接的协议,每次客户端和服务器进行连接时,会有"三次握手"来保证数据的安全性。在数据传输前先在发送端和接收端建立连接,然后在传输数据,它提供了两台计算机之间可靠无差错的数据传输。第一次握手,客户端向服务器端发出连接请求,等待服务器确认。第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求,第三次握手,客户端再次向服务器端发送确认信息,确认连接。
二、TCP特点
特点:相对于UDP,传输效率低,更安全。一般用于上传下载文件。TCP协议传输时不限制大小。
三、TCP练习(客户端与服务端传输文件)
【客户端】
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户端
* 向服务端上传数据
*/
public class TcpClient {
public static void main(String[] args) throws IOException {
//创建套接字对象,设置主机为localhost,端口号为12306
Socket s = new Socket("localhost", 12306);
//获取输入流
OutputStream os = s.getOutputStream();
//创建文件对象
File f = new File("E:\\1.pdf");
//获取文件名称,为上传文件设置名称
String name = f.getName();
//由于Windows文件命名长度最长为237个字符
//所以如果是GBK编码格式则需要474个字节
//如果是UTF-8编码格式则需要711个字节
//所以1byte是存不下文件名的长度的。
//在服务端需要名称长度,来进行命名。故我们采用两个字节用来存取文件的名称长度,然后在存取名称,最后在存取内容
//写入文件名称长度
os.write(name.getBytes().length / 256);
os.write(name.getBytes().length % 256 - 128);
//写入文件名称
os.write(name.getBytes());
//写入内容
byte[] b = new byte[1024]; //设置缓冲区
int len; //设置内容长度
FileInputStream fis = new FileInputStream(f); //创建字节输出流,读取内容将它输出到os对象中
while((len = fis.read(b)) != -1){
os.write(b, 0, len);
}
//告知服务器输入完毕
s.shutdownInput();
//关流
fis.close();
os.close();
s.close();
}
}
注意:文件名称长度可能超过128,所以我们设置两个字节存储名称长度。
os.write(name.getBytes().length / 256);
os.write(name.getBytes().length % 256 - 128);
所以,我们要向服务端发送名称长度,名称内容,以及文件内容。发送名称长度是为了获得名称内容。
【服务端】
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws IOException {
//创建ServerSocket对象,并设置端口号为12306
ServerSocket ss = new ServerSocket(12306);
//获取套接字对象
Socket socket = ss.accept();
//获取字节输入流
InputStream is = socket.getInputStream();
//获取名称长度
byte len1 = (byte)is.read();
byte len2 = (byte)is.read();
//根据名称设置的规则,获取名称的长度
int len = len1*256 + len2+128;
//设置缓冲区
byte[] b = new byte[len];
//获取文件名称
is.read(b);
System.out.println("E:\\test\\"+new String(b, 0, len));
//创建字节输出流
//并在指定位置,创建文件
FileOutputStream fos = new FileOutputStream(new File("E:\\test\\"+new String(b, 0, len)));
//写入内容
while((len = is.read(b)) != -1){
fos.write(b, 0, len);
}
//告知客户端接收完毕
socket.shutdownInput();
//关流
fos.close();
is.close();
socket.close();
ss.close();
}
}
大家要注意:
byte len1 = (byte)is.read();
byte len2 = (byte)is.read();
一定要将其内容强转为byte类型。