提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
计算机网络OSI网络模型的五层协议:应用层,运输层,网络层,数据链路层,物理层。
而TCP编程则是基于运输层,负责控制传输数据,它在传输数据之前需要先建立连接,建立连接后才能传输数据,传输完后还需要断开连接。
TCP协议是一种面向连接,可靠传输的协议
一、Socket是什么?
Socket是一个抽象概念,一个应用程序通过一个Socket来建立一个远程连接,而Socket内部通过TCP/IP协议把数据传输到网络。
Socket、TCP和部分IP的功能都是由操作系统提供的,不同的编程语言只是提供了对操作调用的简单的封装。例如:Java提供的几个Socket相关的类就封装了操作系统提供的接口:ServerSocket类、Socket类。
二、实践案例(基于TCP协议用Socket模拟服务器和客户端)
1.案例功能
- 通过使用ServerSocket模拟服务器,用socket模拟客户端,用客户端向服务器端发送本地磁盘的照片文件,服务端接受文件后保存并向客户端反馈信息。
2.源码及解析
- ServerSocket模拟的服务器端
注:自定义端口号范围在1025~65535之间,小于1024的端口属于特权端口,需要管理员权限,大于1024的端口可以由任意用户的应用程序打开。
public class FileServer {
public static void main(String[] args) {
//监听指定端口号:
try (ServerSocket server = new ServerSocket(8008)) { //通过死循环,可以让服务器一直处于等待(阻塞)状态
while(true) {
// 让服务器处于等待状态(阻塞)
// accpet()方法返回Socker实例
Socket client = server.accept();
System.out.println("链接成功......");
//获取客户端主机名作为接收文件后的文件名
String fileName = String.format("%s.jpg",client.getInetAddress().getHostName());
//用try-with-resources机制,可以在程序运行结束时自动关闭流
try(
//获取字节输入流(用于接收服务器信息)
BufferedInputStream bis = new BufferedInputStream(client.getInputStream());
//创建字节输出流(用于向本地写入接受的文件)
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\test\\upload\\"+fileName));
// 获取字节输出流(用于发送信息至客户端)
OutputStream out = client.getOutputStream()){
//进行写入
byte[] buff = new byte[1024];
int len = -1;
while((len=bis.read(buff))!=-1){
bos.write(buff,0,len);
}
//强制输出缓冲区至网络中
bos.flush();
//向客户端发送“反馈信息”
out.write("文件上传成功".getBytes(StandardCharsets.UTF_8));
out.flush();
}
}
}catch(IOException e){
}
}
}
- Socket模拟的客户端
public class FileClient {
public static void main(String[] args) {
//指定主机ip地址和要连接的端口号
try (Socket socket = new Socket("172.20.10.2", 8008)) {
try (
//获取字节输出流(用于发送客户端信息)
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
//创建字节输入流(读取本地要上传的文件)
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("D:\\test\\bbb\\GG-Bond.jpg"));
// 获取字节输入流(用于读取服务器端信息)
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()))
) {
byte[] buff = new byte[1024];
int len = -1;
while ((len = bis.read(buff)) != -1) {
bos.write(buff, 0, len);
}
bos.flush();
//关闭本次socket的输出流
//因为服务器是通过网络向客户端发送文件,而不是本地磁盘中获取,所以在传输完毕后要前端socket的输出流,
//以保证程序能正常执行,否则程序会卡在循环中无法向下运行,从而无法读取反馈信息
socket.shutdownOutput();
// 读取服务器信息
String message = br.readLine();
//因为服务器端反馈的是字节信息,所以要进行处理
message=new String(message.getBytes(),StandardCharsets.UTF_8);
System.out.println(message);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.运行结果
总结
使用Java进行TCP编程时,需要使用Socket模型:
- 服务器端用ServerSocket监听指定端口; 客户端使用Socket(InetAddress, port)连接服务器;
- 服务器端用accept()接收连接并返回Socket实例;
- 多个客户端同时连接进来,ServerSocket会把连接扔到队列里,然后一个一个处理;
- TCP编程有着可靠、稳定、有序、点对点的特点。