【网络编程】TCP Socket编程

2023-09-16 19:07:03

流套接字: 使用传输层TCP协议
TCP: 即Transmission Control Protocol(传输控制协议),传输层协议。
TCP的特点:

  1. 有连接
  2. 可靠传输
  3. 面向字节流
  4. 有接收缓冲区,也有发送缓冲区
  5. 大小不限

1. ServerSocket

ServerSocket 是创建TCP服务端Socket的API。

注意: ServerSocket 只能用于 服务器端。

构造方法:

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

方法:

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

2. Socket

Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。

构造方法:

方法签名方法说明
Socket(String host, int port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

注意:这里面的 host 和 port 是要连接的服务器的 IP 地址和端口号。

方法:

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

3. TCP的长短连接

TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:

短连接: 每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收数据。
长连接: 不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。

两者区别如下:

  1. 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
  2. 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
  3. 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。

4. Socket 通信模型

在这里插入图片描述

5. 代码示例:TCP 回显服务器

服务器代码:

class TcpEchoServer {
    public ServerSocket serverSocket;//专门用来接受请求并建立链接
    public Socket clientSocket;//专门用来处理请求
    public TcpEchoServer(int port) throws IOException {
        this.serverSocket=new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        //也可以利用线程池
        ExecutorService threadsPool= Executors.newCachedThreadPool();
        while(true){
            //接受请求
            clientSocket=serverSocket.accept();
//            //利用多线程才能让服务器同时处理多个客户端的请求
//            Thread t=new Thread(()->{
//                //建立链接并处理请求
//                try {
//                    createConnection(clientSocket);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            });
//            t.start();
            //创建线程池相对于每次创建一个线程来说效率更高一些
            threadsPool.submit(()->{
                try {
                    createConnection(clientSocket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

    public void createConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d]建立链接成功\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        //三个步骤
        //1.读取客户端请求(根据打开的文件流确定了读取的是客户端发来的请求)
        //这里针对TCP的读写和对于文件的读写是一摸一样的
        //利用socket构造文件流
        try(InputStream inputStream=clientSocket.getInputStream()){//注意打开的流
            //直接利用scanner读取(利用原生的InputStream也是可以的,但Scanner更方便)
            Scanner scanner=new Scanner(inputStream);
            try(OutputStream outputStream=clientSocket.getOutputStream()){//注意打开的流
                while(true){
                    
                    if(!scanner.hasNext()){
                        System.out.printf("[%s:%d]断开链接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
                        break;
                    }
                    //读取请求(TCP以字符流进行传输)
                    // 读到空白符/ 空格/换行才会停止
                    String request=scanner.next();
                    //2.根据请求计算响应
                    String response=process(request);
                    //3.返回响应(根据打开的文件流决定了是往客户端返回请求)
                    //为了方便用PrintWriter对OutputStream进行包裹
                    PrintWriter printWriter=new PrintWriter(outputStream);
                    // 因为使用 next,读到空白符/ 空格/换行才会停止,所以须使用 println 
                    printWriter.println(response);
                    printWriter.flush();
                    System.out.printf("[%d][req:%s resp:%s]\n",clientSocket.getPort(),request,response);
                }
            }
        }finally {
            clientSocket.close();//记得及时关闭
        }
    }

    public String process(String request){
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer tcpEchoServer=new TcpEchoServer(9090);
        tcpEchoServer.start();
    }
}

客户端代码:

class TcpEchoClient {
    public Socket client;
    //TCP中客户端构造函数的ip和port指的是要链接的服务器的IP和port
    public TcpEchoClient(String serverIp, int serverPort) throws IOException {
        this.client = new Socket(serverIp, serverPort);
    }

    public void start() throws IOException {
        System.out.println("和服务器建立链接成功");
        Scanner scanner = new Scanner(System.in);
        //这里针对TCP的读写和对于文件的读写是一摸一样的
        //利用socket构造文件流
        try (InputStream inputStream = client.getInputStream()) {
            try (OutputStream outputStream = client.getOutputStream()) {
                //接收从控制台输入的字符串
                while (true) {
                    System.out.println("->");
                    String request = scanner.next();
                    //构造请求并发送请求(PrintWriter和Scanner对应)//注意文件流
                    PrintWriter printWriter = new PrintWriter(outputStream);
                    // 因为使用 next,读到空白符/ 空格/换行才会停止,所以须使用 println 
                    printWriter.println(request);
                    printWriter.flush();//如果不及时刷新,服务器可能不能及时接收到数据
                    //接收响应
                    Scanner respScanner = new Scanner(inputStream);
                    String response = respScanner.next();
                    //显示到控制台上
                    System.out.printf("[req:%s  resp:%s]\n", request, response);
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1", 9090);
        tcpEchoClient.start();
    }
}

注意:当然要先启动服务器再启动客户端!

好啦! 以上就是对 TCP Socket编程的讲解,希望能帮到你 !
评论区欢迎指正 !

更多推荐

基于Java个性化美食推荐系统设计实现(源码+lw+部署文档+讲解等)

博主介绍:✌全网粉丝30W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌🍅文末获取源码联系🍅👇🏻精彩专栏推荐订阅👇🏻不然下次找不到哟2022-2024年最全的计算机软件毕业设计选题

基于香橙派和SU-03T 使用Linux实现语音控制刷抖音

硬件介绍SU-03T之前在小车的时候使用过,详见:语音小车---6+最终整合_mjmmm的博客-CSDN博客按照下图进行接线:项目需求通过语音指令来控制安卓手机刷抖音,可以实现视频切换和点赞等功能:1.开机播报“你好,我是你的刷抖音助手”1.当说出“你好抖音助手"可以唤醒模块,模块回复“抖音助手在”2.当超过10s没有

七天学会C语言-第一天(C语言基本语句)

一、固定格式这个是C程序的基本框架,需要记住!!!#include<stdio.h>intmain(){return0;}二、printf语句简单输出一句C程序:#include<stdio.h>intmain(){printf("大家好,");printf("我是");printf("沐尘而生!");return0;

9月15日、9月18日上课内容 Zookeeper集群 + Kafka集群

Zookeeper本章结构Zookeeper概述Zookeeper定义*(了解)Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。Zookeeper工作机制*****(非常重要,需要掌握)Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和

Cobol学习笔记(整理中80%)

1.数据类型1.1变量定义序号数据名PIC数据类型[VALUE值].例:03MY-IDPIC999[VALUE123].数据类型写几个长度就是几。1.2数据类型1.2.1数值型9:数值型,99999缩写9(5),不满位前补0,0有(+)符号。S:正负数值,S9999缩写S9(4),不满位前补0,值有正负符号。V:小数,

Linux下运行Jmeter压测

一、在Linux服务器先安装SDK1、先从官网下载jdk1.8.0_131.tar.gz,再从本地上传到Linux服务器2、解压:tar-xzfjdk1.8.0_131.tar.gz,生成文件夹jdk1.8.0_1313、在/usr/目录下创建java文件夹,再将jdk1.8.0_131目录移动到/usr/java中1

【Linux从入门到精通】多线程 | 线程互斥(互斥锁)

上篇文章我们对线程|线程介绍&线程控制介绍后,本篇文章将会对多线程中的线程互斥与互斥锁的概念进行详解。同时结合实际例子解释了可重入与不被重入函数、临界资源与临界区和原子性的概念。希望本篇文章会对你有所帮助。文章目录引入一、重入与临界1、1可重入与不被重入函数1、1、1不可重入函数1、1、2可重入函数1、2临界资源与临界

手撕单链表

>作者简介:დ旧言~,目前大一,现在学习Java,c,c++,Python等>座右铭:松树千年终是朽,槿花一日自为荣。>望小伙伴们点赞👍收藏✨加关注哟💕💕🌟前言前面我们已经学习了顺序表,顺序表可以存储动态的数据,但是一旦元素过少,而又要开辟空间,这样就造成空间的浪费,为了解决这类问题,人们发现了单链表,把一个一

QQ邮箱怎么设置SMTP接口服务器?

在现如今信息快速传递的时代,邮件已成为我们工作、学习和生活中必不可少的一部分。而作为每位用户必备的一款邮箱,QQ邮箱一直以其稳定、高效、安全的特点深受大家的青睐。但是你是否觉得每次发邮件都需要打开QQ邮箱网页,进行繁琐的操作很是麻烦呢?其实,QQ邮箱也提供了SMTP接口服务器,使得我们可以直接调用SMTP接口,让发信更

如何通过bat批处理实现快速生成文件目录,一键生成文件名和文件夹名目录

碰对了情人,相思一辈子。具体方法步骤:一、创建一个执行bat文件(使用记事本即可);1、新建一个txt文本空白记事本文件2、复制以下内容进记事本内dir/a/s/b>LIST.TXT(其中LIST.TXT文件名是提取后将要自动新建的文本文件)二、记事本保存,文件名可以任意写三、把保存的文件名后缀.txt改为.bat,这

网络路径监控分析

不间断的连接应该是任何企业的首要任务。然而,确保网络中的源和目标之间持续、不间断的联系一直是网络通信中一个劳动密集型的过程。了解网络路径中的障碍、识别它们并迅速解决它们以维护健康、不间断的网络至关重要。为什么要监控网络路径维护网络运行状况是任何LAN或WAN网络中最重要的因素。在数据传输期间,无法查明和排查网络路径中跃

热文推荐