网络编程套接字之三【TCP】

这篇具有很好参考价值的文章主要介绍了网络编程套接字之三【TCP】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1. ServerSocket API(给服务器端使用的类)

2. Socket API(既给服务器使用,也给客户端使用)

3. 写TCP回显—服务器

4. 使用线程池后的TCP服务器代码(最终)

5. 写回显-客户端

6. TCP回显—客户端代码

7. 运行回显服务器和客户端


TCP流套接字编程

1. ServerSocket API(给服务器端使用的类)

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

 构造方法

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

方法

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

2. Socket API(既给服务器使用,也给客户端使用)

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

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

构造方法

方法签名 说明
Socket(String host, int port)

创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的

进程建立连接(尝试和指定的服务器建立连接)

方法

方法签名 说明
InetAddress getInetAddress() 返回套接字所连接的地址(返回套接字获取到对方的IP地址和端口)
InputStream getInputStream() 返回此套接字的输入流(通过Socket可以获取到两个流对象,分别用来读和写)
OutputStream getOutputStream() 返回此套接字的输出流

3. 写TCP回显—服务器

1.先写一个ServerSocket对象

    private ServerSocket listenSocket = null;

2.下面写Tcp服务器构造方法

    public TcpEchoServer(int port) throws IOException {
     listenSocket = new ServerSocket(port);
    }

3.写一个启动服务器的方法start(),在start中写上while循环来执行

   a)调用accept来接收客户端的连接

   b)再处理这个连接,这里写一个processConnection()方法来处理

    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true) {
            //1. 先调用 accept 来接受客户端的连接
            Socket clientSocket = listenSocket.accept();
            //2. 再处理这个连接
            processConnection(clientSocket);
        }
   }

4.下面来写这个processConnection()方法,处理连接客户端连接

   方法中写try(这里写上InputStream(读)和OutPutStream(写)对象,写在try中帮助资源回收) {这里写上写具体处理逻辑步骤}

注意最后必须要写上finally来close关闭clientSocket

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n",
                clientSocket.getInetAddress().toString(),
                clientSocket.getPort());
        //接下来处理客户端请求
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {
            while(true) {
           
            }
        }finally {
            //这里要关闭socket,是因为
            //socket也是一个文件,一个进程能够同时打开的文件个数有上限(PCB文件描述符表,不是无限的
            clientSocket.close();
        }
    }

   a)读取请求并解析

                Scanner scanner = new Scanner(inputStream);
                if(!scanner.hasNext()) {
                    //读完了,连接可以断开了
                    System.out.printf("[%s:%d] 客户端下线!\n",
                            clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                String request = scanner.next();

   b)根据请求计算响应(这里写一个process方法)

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

 c)响应写回到客户端

                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                //刷新缓冲区确保数据确实通过网卡发送出去了
                printWriter.flush();

   d)将发送的信息显示到服务器界面上

                System.out.printf("[%s:%d] req: %s; resp: %s\n",
                        clientSocket.getInetAddress().toString(),
                        clientSocket.getPort(),
                        request,response);

5.最后再写上mian方法来执行服务器

    public static void main(String[] args) throws IOException {
        TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);
        tcpEchoServer.start();
    }
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;
import java.util.concurrent.Semaphore;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 28463
 * Date: 2022—10—14
 * Time: 17:05
 */
public class TcpEchoServer {
    //代码中会设计到多个 socket 对象,使用不同的名字来区分
    private ServerSocket listenSocket = null;

    public TcpEchoServer(int port) throws IOException {
     listenSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true) {
            //1. 先调用 accept 来接受客户端的连接
            Socket clientSocket = listenSocket.accept();
            //2. 再处理这个连接
            processConnection(clientSocket);
        }
    }

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n", 
                clientSocket.getInetAddress().toString(),
                clientSocket.getPort());
        
        //接下来处理客户端请求
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {
            while(true) {
                //1.读取请求并解析
                Scanner scanner = new Scanner(inputStream);
                if(!scanner.hasNext()) {
                    //读完了,连接可以断开了
                    System.out.printf("[%s:%d] 客户端下线!\n", 
                            clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                String request = scanner.next();
                //2.根据请求计算响应
                String response = process(request);
                //3.响应写回到客户端
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                //刷新缓冲区确保数据确实通过网卡发送出去了
                printWriter.flush();

                System.out.printf("[%s:%d] req: %s; resp: %s\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 {
        TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);
        tcpEchoServer.start();
    }
}

 下面思考为啥代码最后finally要执行clientSocket的close,而前面的listenSocket以及UDP程序中的socekt为啥就没close?

mfc创建tcp服务器线程,JavaEE,java

但是上面的代码有个问题,只能处理一个客户端的请求,(本质上第二个客户端的消息是发出去了,但服务器此时还在执行第一个客户端的请求,只要从第一个客户端这里出来,服务器就会立刻执行第二个客户端的消息)

我们希望的是既能够快速重复的调用到accept(也就是连接多个客户端),又能够循环的处理客户端的请求。所以就需要使用到多线程了

mfc创建tcp服务器线程,JavaEE,java

那么为什么前面UDP就不需要考虑这个问题,而TCP需要考虑 

UDP是无连接,客户端直接发消息就行(不必专注于处理某一个客户端)

TCP建立连接之后,要处理客户端的多次请求,才导致无法快速的调用到accept(长连接)(主要原因)

如果TCP每个连接只处理一个客户端的请求,也能够保证快速调用到accept(短连接)

 下面使用多线程,给每个客户端连上来的都分配一个新的线程负责处理请求

mfc创建tcp服务器线程,JavaEE,java

 但是直接这样使用多线程,如果循环多次,对应就会创建很多线程,等线程执行完,又会消毁很多的线程,所以更好的方法就是使用线程池

mfc创建tcp服务器线程,JavaEE,java

4. 使用线程池后的TCP服务器代码(最终)

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;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 28463
 * Date: 2022—10—14
 * Time: 17:05
 */
public class TcpEchoServer {
    //代码中会设计到多个 socket 对象,使用不同的名字来区分
    private ServerSocket listenSocket = null;

    public TcpEchoServer(int port) throws IOException {
     listenSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        ExecutorService service = Executors.newCachedThreadPool();
        while(true) {
            //1. 先调用 accept 来接受客户端的连接
            Socket clientSocket = listenSocket.accept();
            //2. 再处理这个连接,这里应该要使用多线程,每个客户端连上来都分配一个新的线程负责处理
            service.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnection(clientSocket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n",
                clientSocket.getInetAddress().toString(),
                clientSocket.getPort());

        //接下来处理客户端请求
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()) {
            while(true) {
                //1.读取请求并解析
                Scanner scanner = new Scanner(inputStream);
                if(!scanner.hasNext()) {
                    //读完了,连接可以断开了
                    System.out.printf("[%s:%d] 客户端下线!\n",
                            clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                String request = scanner.next();
                //2.根据请求计算响应
                String response = process(request);
                //3.响应写回到客户端
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                //刷新缓冲区确保数据确实通过网卡发送出去了
                printWriter.flush();

                System.out.printf("[%s:%d] req: %s; resp: %s\n",
                        clientSocket.getInetAddress().toString(),
                        clientSocket.getPort(),
                        request,response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //这里要关闭socket,是因为
            //socket也是一个文件,一个进程能够同时打开的文件个数有上限(PCB文件描述符表,不是无限的
            clientSocket.close();
        }
    }

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

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

5. 写回显-客户端

 1. 先写一个Socket对象,客户端用Socket来建立连接

private Socket socket = null;

2.下面写Tcp客户端构造(和Udp区别较大,有连接和无连接的区别)

    public TcpEchoClient(String serverIP, int serverPort) throws IOException {
        //和服务器建立连接,就需要知道服务器在哪
        socket = new Socket(serverIP,serverPort);
    }

3.写客户端执行方法start(),给start里面放try,try中执行的就是while,来让客户端循环输入,还要在try后面括号中写上InputStream(读)和OutputStream(写)的对象(写在括号中中try会自动帮助,关掉资源)

    public void start() throws IOException {
        Scanner scan = new Scanner(System.in);
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()) {
            while(true) {

            }
         }
    }

while中写  a)从控制台读取数据,构造一个请求

                System.out.println("-> ");
                String request = scan.next();

                 b)发送请求给服务器(PrintWriter)

                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                //这个 flush 不要忘记,否则可能导致请求没有真发出去
                printWriter.flush();

                 c)从服务器读取响应

                Scanner respScanner = new Scanner(inputStream);
                String response = respScanner.next();

                 d)把响应显示到界面上

                System.out.println(response);

4.最后再写上mian方法来执行客户端

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

 Udp和Tcp构造的区别,有连接和无连接 

mfc创建tcp服务器线程,JavaEE,java

6. 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;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 28463
 * Date: 2022—10—14
 * Time: 17:06
 */
public class TcpEchoClient {
    //客户端需要使用这个 Socket 对象来建立连接
    private Socket socket = null;

    public TcpEchoClient(String serverIP, int serverPort) throws IOException {
        //和服务器建立连接,就需要知道服务器在哪
        socket = new Socket(serverIP,serverPort);
    }

    public void start() throws IOException {
        Scanner scan = new Scanner(System.in);
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()) {
            while(true) {
                //1.从控制台读取数据,构造成一个请求
                System.out.println("-> ");
                String request = scan.next();

                //2.发送请求给服务器
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                //这个 flush 不要忘记,否则可能导致请求没有真发出去
                printWriter.flush();

                //3.从服务器读取响应
                Scanner respScanner = new Scanner(inputStream);
                String response = respScanner.next();

                //4.把响应显示到界面上
                System.out.println(response);
            }
        }
    }

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

7. 运行回显服务器和客户端

mfc创建tcp服务器线程,JavaEE,java

 mfc创建tcp服务器线程,JavaEE,javamfc创建tcp服务器线程,JavaEE,java

 mfc创建tcp服务器线程,JavaEE,java文章来源地址https://www.toymoban.com/news/detail-805067.html

到了这里,关于网络编程套接字之三【TCP】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【网络编程】网络编程套接字(三)TCP网络程序

    与前边的UDP网络程序相同,创建套接字的接口都是socket,下边对socket接口进行介绍: 协议家族选择AF_INET,因为我们要进行网络通信。 而第二个参数,为服务类型,传入SOCK_STREAM,我们编写TCP程序,所以要选择流式的服务。 第三个参数默认传入0,由前两个参数就可以推出这是

    2024年02月16日
    浏览(36)
  • 【Linux网络】网络编程套接字(TCP)

    目录 地址转换函数 字符串IP转整数IP 整数IP转字符串IP 关于inet_ntoa 简单的单执行流TCP网络程序 TCP socket API 详解及封装TCP socket  服务端创建套接字  服务端绑定  服务端监听  服务端获取连接  服务端处理请求 客户端创建套接字 客户端连接服务器 客户端发起请求 服务器测试

    2024年03月21日
    浏览(44)
  • 【Linux】网络---->套接字编程(TCP)

    TCP的编程流程:大致可以分为五个过程,分别是准备过程、连接建立过程、获取新连接过程、消息收发过程和断开过程。 1.准备过程:服务端和客户端需要创建各自的套接字,除此之外服务端还需要绑定自己的地址信息和进行监听。注意:服务端调用listen函数后,处理监听状

    2024年02月04日
    浏览(39)
  • Linux网络编程——tcp套接字

    本章Gitee仓库:tcp套接字 客户端: 客户端: 关于构造和初始化,可以直接在构造的时候,将服务器初始化,那为什么还要写到 init 初始化函数里面呢? 构造尽量简单一点,不要做一些“有风险”的操作。 tcp 是面向连接的,通信之前要建立连接,服务器处于等待连接到来的

    2024年02月20日
    浏览(33)
  • 网络编程套接字(2)——简单的TCP网络程序

    我们将TCP服务器封装成一个类,当我们定义出一个服务器对象后需要马上对服务器进行初始化,而初始化TCP服务器要做的第一件事就是创建套接字。 TCP服务器在调用socket函数创建套接字时,参数设置如下: 协议家族选择 AF_INET ,因为我们要进行的是网络通信。 创建套接字时

    2024年02月06日
    浏览(37)
  • 【Linux网络编程】网络编程套接字(TCP服务器)

    作者:爱写代码的刚子 时间:2024.4.4 前言:本篇博客主要介绍TCP及其服务器编码 只介绍基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP地址 但是我们通常用点分十进制的字符串表示IP地址,以下函数可以在字符串表示和in_addr表示之间转换 字符串转in

    2024年04月14日
    浏览(45)
  • TCP/IP网络编程(一) 理解网络编程和套接字

    网络编程和套接字概要 网络编程就是编写程序使两台联网的计算机相互交换数据 为了与远程计算机进行数据传输,需要连接因特网,而编程种的套接字就是用来连接该网络的工具。 构建套接字 1.调用soecket函数创建套接字 2.调用bind函数给套接字分配地址 3.调用listen函数将套

    2024年02月11日
    浏览(42)
  • 【网络通信】socket编程——TCP套接字

    TCP依旧使用代码来熟悉对应的套接字,很多接口都是在udp中使用过的 所以就不会单独把他们拿出来作为标题了,只会把第一次出现的接口作为标题 通过TCP的套接字 ,来把数据交付给对方的应用层,完成双方进程的通信 在 tcpServer.hpp 中,创建一个命名空间 yzq 用于封装 在命名

    2024年02月13日
    浏览(29)
  • JavaEE-网络编程套接字(UDP/TCP)

    下面写一个简单的UDP客户端服务器流程 思路: 对于服务器端:读取请求,并解析– 根据解析出的请求,做出响应(这里是一个回显,)–把响应写回客户端 对于客户端:从控制台读取用户输入的内容–从控制台读取用户输入的内容–从控制台读取用户输入的内容–将其显示在

    2024年02月07日
    浏览(35)
  • C++网络编程 TCP套接字基础知识,利用TCP套接字实现客户端-服务端通信

    流式套接字编程针对TCP协议通信,即是面向对象的通信,分为服务端和客户端两部分。 1)加载套接字库( 使用函数WSAStartup() ),创建套接字( 使用socket() ) 2)绑定套接字到一个IP地址和一个端口上( 使用函数bind() ) 3)将套接字设置为监听模式等待连接请求( 使用函数

    2024年02月03日
    浏览(36)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包