TCP流套接字编程(模拟多个客户端与服务器交互)

这篇具有很好参考价值的文章主要介绍了TCP流套接字编程(模拟多个客户端与服务器交互)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、ServerSocket API

1.1、ServerSocket构造方法

1.2、ServerSocket方法

二、Socket API 

2.1、socket构造方法 

2.2、socket方法

三、TCP 中的长短连接

四、示例 

实现聊天室功能

五、存在的问题 


一、ServerSocket API

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

1.1、ServerSocket构造方法

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

1.2、ServerSocket方法

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

二、Socket API 

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

不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,以及用来与对方收发数据的。

2.1、socket构造方法 

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

2.2、socket方法

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

三、TCP 中的长短连接

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

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

对比以上长短连接,两者区别如下:

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

四、示例 

实现聊天室功能

  1. 客户端先接收键盘输入,循环接收客户端输入内容,发起聊天。
  2. 发送请求:用户输入的数据封装为输出流,发送到服务端 。
  3. 服务端接收并处理请求:接收请求数据,根据该请求数据来计算响应。
  4. 服务端返回响应:将响应数据封装为输出流,返回给客户端。
  5. 客户端接收响应:简单的打印输出所有的响应内容。

1、基于TCP的客户端


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

/**
 * 基于TCP的客户端
 */
public class TCPEchClient {
    //生命Socket对象
    public Socket socket;
    //通过构造方法来初始化Socket,指定IP地址,端口
    public TCPEchClient(String ServerIp, int port) throws IOException {
        //根据服务器的IP与端口号创建Socket对象
        this.socket=new Socket(ServerIp,port);
    }
    public void start(){
        System.out.println("客户端已启动...");
        try {
            InputStream inputStream=socket.getInputStream();
            OutputStream outputStream=socket.getOutputStream();
            //循环接收用户的输入
            while(true){
                System.out.print("->");
                Scanner sc=new Scanner(System.in);
                String request=sc.nextLine();
                if(request==null||request.equals("")){
                    System.out.println("输入内容不能为空!!!");
                    continue;
                }
                //2、把用户的输入封装到输出流中,可以用PrintWriter简化操作
                PrintWriter writer=new PrintWriter(outputStream);
                //3、把数据发送出去(写数据)
                writer.println(request);
                //强制刷新缓冲区
                writer.flush();
                //4、接收服务器的响应
                Scanner responseSc=new Scanner(inputStream);
                //5、解析相应的数据
                String response=responseSc.nextLine();
                //6、打印日志
                System.out.printf("request=%s,response=%s\n",request,response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //初始化客户端
    public static void main(String[] args) throws IOException {
        TCPEchClient tcpEchClient=new TCPEchClient("127.0.0.1",9090);
        tcpEchClient.start();
    }
}

2、基于TCP的服务端


import tcp.TCPEchoSever;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**
 * 基于TCP的服务端
 */
public class TCPEchServer {
    //声明一个服务端的类
    public ServerSocket socket;
    //构造方法,初始化对象
    public TCPEchServer(int port) throws IOException {
        //校验端口
        if(port<1||port>65535){
            throw new RuntimeException("端口号建议在1025~65535之间");
        }
        //根据指定的端口号初始化Socket服务
        this.socket=new ServerSocket();
    }
    public void start() throws IOException {
        System.out.println("服务已启动等待客户端连接...");
        //循环接收服务器连接
        while(true){
            //接收客户端请求
            Socket clientSocket=socket.accept();
            //接收到客户端连接之后,交给专门处理连接的方法。
            processConnection(clientSocket);
        }
    }

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s %d]客户端已上线.\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        //所有的通信数据都在Socket对象中clientSocket,Tcp传输的数据是字节流的形式
        //1、获取输入输出流
        try {
            InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream();
            //循环处理客户端发来的请求
            while(true){
                //Scanner简化字符串的获取
                Scanner sc=new Scanner(inputStream);
                //判断是否还有数据
                if(!sc.hasNextLine()){
                    System.out.printf("[%s:%d] 客户端已下线.\n",
                            clientSocket.getInetAddress().toString(),clientSocket.getPort());
                    break;
                }
                //获取用户发来的请求
                String request=sc.nextLine();
                String response=process(request);
                //把响应返回给客户端
                PrintWriter writer=new PrintWriter(outputStream);
                //强制刷新缓冲区
                writer.flush();
                System.out.printf("[%s:%d]request=%s,response=%d\n",clientSocket.getInetAddress().toString()
                        ,clientSocket.getPort(),request,response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            //关闭客户端连接
            clientSocket.close();
        }
    }

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

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

3、封装响应数据

import java.io.IOException;
import java.util.Scanner;

public class TCPMsgServer extends TCPEchoSever {

    public TCPMsgServer(int port) throws IOException {
        super(port);
    }

    //实现一个聊天的功能
    @Override
    protected String process(String request) {
        //1.打印发送方发来的消息
        System.out.println("->"+request.toString());
        //2.回复对方的消息
        Scanner sc=new Scanner(System.in);
        String response=sc.nextLine();
        //3.返回消息
        return response;
    }

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

运行结果:

TCP流套接字编程(模拟多个客户端与服务器交互),tcp/ip,网络,服务器

五、存在的问题 

1、首先将客户端类对象设置为多实例创建状态,这样就可以创建出多个客户端对象

TCP流套接字编程(模拟多个客户端与服务器交互),tcp/ip,网络,服务器

2、创建第二个客户端时,并没有按预想的连接服务端成功

TCP流套接字编程(模拟多个客户端与服务器交互),tcp/ip,网络,服务器 3、出现这个现象的原因

TCP流套接字编程(模拟多个客户端与服务器交互),tcp/ip,网络,服务器

4、如何去解决这个问题,实现多个客户端呢?这时就需要引入多线程来执行任务。

利用线程来执行不同的客户端任务,就需要创建一个线程服务端类,该类继承服务端类,重写start()方法。

import tcp.TCPEchoSever;
import java.io.IOException;
import java.net.Socket;

public class TCPThreadServer extends TCPEchoSever {
    public TCPThreadServer(int port) throws IOException {
        super(port);
    }
    @Override
    public void start() throws IOException {
        System.out.println("服务已启动,等待客户端连接.....");
        //循环接收服务器的连接
        while(true){
            //接收客户端请求
            Socket clientSocket = socket.accept();
            //为每一个连接创建线程
            Thread thread=new Thread(() ->{
                //接收到客户端连接之后,交给专门处理连接的方法
                try {
                    //在子线程中处理连接
                    processConnection(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            //启动线程
            thread.start();
        }
    }

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

运行结果:

TCP流套接字编程(模拟多个客户端与服务器交互),tcp/ip,网络,服务器

5、手动创建线程太过麻烦,可以利用线程池来进行创建线程 ,还是跟上述操作差不过,重写start()方法文章来源地址https://www.toymoban.com/news/detail-545252.html

import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TCPThreadPoolServer extends TCPEchServer {

    public TCPThreadPoolServer(int port) throws IOException {
        super(port);
    }

    @Override
    public void start() throws IOException {
        System.out.println("服务已启动,等待客户端上线...");
        //创建一个线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3,
                10,
                1,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10)); //阻塞队列可存10个服务器
        //循环接收连接
        while (true) {
            //接收客户端请求
            Socket clientSocket = socket.accept();
            //把处理请求连接的操作,加入到线程池中
            threadPool.submit(() -> {
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }
    public static void main(String[] args) throws IOException {
        TCPThreadPoolServer server=new TCPThreadPoolServer(9090);
        server.start();
    }
}

到了这里,关于TCP流套接字编程(模拟多个客户端与服务器交互)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 计算机网络套接字编程实验-TCP单进程循环服务器程序与单进程客户端程序(简单回声)

    1.实验系列 ·Linux NAP-Linux网络应用编程系列 2.实验目的 ·理解并掌握在程序运行时从命令行读取数据的C语言编程方法; ·理解并掌握基于命令参数设置并获取IP与Port的C语言编程方法; ·理解并掌握套接字地址的数据结构定义与地址转换函数应用; ·理解并掌握网络字节序

    2024年02月11日
    浏览(97)
  • 【Python】Python 网络编程 ( Socket 套接字简介 | Socket 套接字使用步骤 | Socket 套接字服务端与客户端开发 )

    Socket 套接字 是一种 进程之间的 通信机制 , 通过套接字可以在 不同的进程之间 进行数据交换 ; 在 网络编程 中 , Socket 套接字 主要用于 客户端 与 服务器 之间的 通信 , 大部分 网络相关的应用程序 , 都使用到了 Socket 套接字技术 ; 套接字有两种类型 : 流套接字 : 提供了一个可

    2024年02月15日
    浏览(153)
  • 【网络编程】网络套接字&udp通用服务器和客户端

    端口号(port)是传输层协议的内容: 端口号是一个2字节16位的整数(uint16) 端口号用来标识主机上的一个进程 IP地址+port能够标识网络上的某一台主机和某一个进程 一个端口号只能被一个进程占用 此处我们先对TCP(Transmission Control Protocol 传输控制协议) 有一个直观的认识,后面再

    2024年02月16日
    浏览(214)
  • Linux网络编程:Socket套接字编程(Server服务器 Client客户端)

    文章目录: 一:定义和流程分析 1.定义 2.流程分析  3.网络字节序 二:相关函数  IP地址转换函数inet_pton inet_ntop(本地字节序 网络字节序) socket函数(创建一个套接字) bind函数(给socket绑定一个服务器地址结构(IP+port)) listen函数(设置最大连接数或者说能同时进行三次握手的最

    2024年02月12日
    浏览(85)
  • 【计算机网络】网络编程套接字&UDP服务器客户端的简单模拟

    需要云服务器等云产品来学习Linux的同学可以移步/–腾讯云–/官网,轻量型云服务器低至112元/年,优惠多多。(联系我有折扣哦) 每台主机都有自己的IP地址,当数据在进行通信的时候,除了要发送的数据外,在报头里面还要包含发送方的IP和接收方的IP,这里发送方的IP就

    2024年02月20日
    浏览(64)
  • Linux网络编程:线程池并发服务器 _UDP客户端和服务器_本地和网络套接字

    文章目录: 一:线程池模块分析 threadpool.c 二:UDP通信 1.TCP通信和UDP通信各自的优缺点 2.UDP实现的C/S模型 server.c client.c 三:套接字  1.本地套接字 2.本地套 和 网络套对比 server.c client.c threadpool.c   server.c client.c server.c client.c

    2024年02月11日
    浏览(66)
  • 【探索Linux】P.29(网络编程套接字 —— 简单的TCP网络程序模拟实现)

    在前一篇文章中,我们详细介绍了UDP协议和TCP协议的特点以及它们之间的异同点。 本文将延续上文内容,重点讨论简单的TCP网络程序模拟实现 。通过本文的学习,读者将能够深入了解TCP协议的实际应用,并掌握如何编写简单的TCP网络程序。让我们一起深入探讨TCP网络程序的

    2024年04月14日
    浏览(87)
  • python套接字(二):实现一个服务器和多客户端连接

    在上一篇博客python套接字(一):socket的使用简单说明了一下套接字的使用,也实现了使用套接字来传输消息,但是也有一个问题,就是这种实现方式只能一个服务器连接一个客户端,意味着有几个个客户就要创建结果服务器,而且客户端直接还不能通信,这样就和现实生活中

    2024年02月14日
    浏览(51)
  • 【JavaEE】网络编程之TCP套接字、UDP套接字

    目录 1.网络编程的基本概念 1.1为什么需要网络编程  1.2服务端与用户端 1.3网络编程五元组  1.4套接字的概念 2.UDP套接字编程 2.1UDP套接字的特点  2.2UDP套接字API 2.2.1DatagramSocket类 2.2.2DatagramPacket类  2.2.3基于UDP的回显程序 2.2.4基于UDP的单词查询  3.TCP套接字编程 3.1TCP套接字的特

    2023年04月20日
    浏览(75)
  • 【JaveEE】网络编程之TCP套接字、UDP套接字

    目录 1.网络编程的基本概念 1.1为什么需要网络编程  1.2服务端与用户端 1.3网络编程五元组  1.4套接字的概念 2.UDP套接字编程 2.1UDP套接字的特点  2.2UDP套接字API 2.2.1DatagramSocket类 2.2.2DatagramPacket类  2.2.3基于UDP的回显程序 2.2.4基于UDP的单词查询  3.TCP套接字编程 3.1TCP套接字的特

    2023年04月13日
    浏览(169)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包