TCP协议特点:
- 面向连接,只能由客户端主动发送数据给服务端,服务端接收到数据后可以给客户端响应
- 通过三次握手建立连接,四次挥手断开连接
- 基于IO流进行数据传输,传输大小没有限制
- 速度慢,传输可靠
使用场景:
- 文件上传下载
- 邮件发送接收
- 远程登陆
TCP通信也叫Socket网络编程
Socket
一个该类对象代表一个客户端程序
- 构造器
public Socket(String host,int port)
使用该方法会立即连接指定服务器程序,如果连接不成功会抛出异常,连接成功表示三次握手通过 - 方法
OutputStream getOutputStream()
获得字节输出流对象
InputStream getInputStream()
获得字节输入流对象 - 流程
1 客户端要求请求与服务器的socket管道连接
2 从socket通信管道获取字节输出流
3 通过字节输出流写出数据
ServerSocket
一个该类对象代表一个服务端程序
- 构造器
public ServerSocket(int port)
- 方法
public Socket accept()
等待接收一个客户端的socket管道请求,连接成功返回一个Socket对象 - 流程
1 注册端口,接收客户端的socket管道连接
2 从socket通信管道获取字节输入流
3 通过字节输入流读取数据
客户端
class TCPClient{
public static void main(String[] args) throws IOException {
System.out.println("客户端启动。。。");
//连接本机端口号7777的程序
Socket socket=new Socket("127.0.0.1",7777);
//获取字节输出流
OutputStream os = socket.getOutputStream();
//将字节输出流包装成打印流
PrintStream ps = new PrintStream(os);
//循环发送消息
while (true){
Scanner scanner = new Scanner(System.in);
System.out.print("请发消息: ");
//打印输入的消息
ps.println(scanner.nextLine());
}
}
}
服务端
class TCPServer{
public static void main(String[] args) throws IOException {
System.out.println("服务端启动。。。");
//指定端口号为7777,要和客户端请求的端口号一致
ServerSocket serverSocket = new ServerSocket(7777);
//循环接收消息
while (true){
//获取一个客户端连接
Socket socket = serverSocket.accept();
//启动一个新的线程去处理
new Server(socket).start();
}
}
}
处理客户端的线程任务
class Server extends Thread{
//封装客户端socket
private Socket socket;
public Server(Socket socket){
this.socket=socket;
}
@Override
public void run() {
try{
//获取字节输入流
InputStream is = socket.getInputStream();
//将字节输入流转为字符输入流
InputStreamReader reader = new InputStreamReader(is);
//将字符输入流包装成缓冲字符输入流
BufferedReader br = new BufferedReader(reader);
//循环读取消息
String msg;
while ((msg=br.readLine())!=null){
System.out.println(socket.getRemoteSocketAddress()+"say: "+msg);
}
}catch (Exception e){
System.out.println(socket.getRemoteSocketAddress()+"下线了");
}
}
}
测试
先设置客户端类运行并发启动
先启动服务端
启动客户端1,输出
启动客户端2,输出
服务端输出:
当关闭某个客户端时,服务端输出:
使用线程池优化:
自定义线程池,设置最大线程数量为3
优点:不会引起系统死极,可以控制并发数量
缺点:并发线程数量受到限制
class ServerThreadPool{
private Executor executor;
public ServerThreadPool(int maxSize,int queueSize){
executor=new ThreadPoolExecutor(maxSize,maxSize,120L, TimeUnit.SECONDS,new ArrayBlockingQueue<>(queueSize));
}
public void execute(Runnable task){
executor.execute(task);
}
}
服务端:
class TCPServer{
public static void main(String[] args) throws IOException {
System.out.println("服务端启动。。。");
ServerSocket serverSocket = new ServerSocket(7777);
//一个服务端对应一个线程池
ServerThreadPool serverThreadPool = new ServerThreadPool(3, 100);
while (true){
Socket socket = serverSocket.accept();
System.out.println("有人上线了");
serverThreadPool.execute(new Server(socket));
}
}
}
测试:
启动服务端和4个客户端
四个客户端分别输出 :我是客户A/B/C/D,服务端只会显示3个
关闭前三个客户端中的一个,服务端打印第四条消息:
转载:https://blog.csdn.net/qq_41112238/article/details/104972727
查看评论