一、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类型。