网络编程_TCP socket

这篇博客详细介绍了TCP流套接字编程,包括ServerSocket和Socket API的使用,并通过一个回显服务案例展示了TCP网络编程的基本流程。在案例中,首先创建ServerSocket监听客户端连接,然后客户端通过Socket建立连接并发送数据。服务器接收到数据后回显,客户端接收并显示。为了支持多个客户端连接,文章讨论了两种实现多线程服务器的方法:一是每个连接启动一个新线程,二是利用线程池管理连接。
摘要由CSDN通过智能技术生成

文章目录

  • TCP流套接字编程
    • ServerSocket API
    • Socket API
    • 案例一

TCP流套接字编程

ServerSocket API

ServerSocket 是创建TCP服务端Socket的API

ServerSocket 构造方法

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

ServerSocket 方法:

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

Socket API

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

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

Socket 构造方法

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

Socket 方法:

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

案例一

回显服务

通过简单的回显服务,了解TCP网络编程的全部过程

image-20220528170151106

此处构造socket并且实例化

接下来构造启动服务器程序方法.因为Tcp和Udp并不一样,Tcp是要先建立连接,所以需要先建立连接,然后对接收到的数据进行处理

image-20220528170605740

执行到processConnection方法,就说明此时服务器和客户端已经建立连接,可以进行一些数据处理的操作了

image-20220528174132240

TcpEchoServer服务端

public class TcpEchoServer {
    private ServerSocket listenSocket = null;

    public TcpEchoServer(int port) throws IOException {
        listenSocket = new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            //建立连接
            Socket socket = listenSocket.accept();
            processConnection(socket);
        }

    }

    private void processConnection(Socket clientSocket) {
        System.out.printf("[%s:%d]建立连接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        try(InputStream inputStream = clientSocket.getInputStream()) {
            try (OutputStream outputStream = clientSocket.getOutputStream()){
                Scanner scanner = new Scanner(inputStream);
                while (true) {
                    if(!scanner.hasNext()){
                        System.out.printf("[%s:%d]断开连接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
                        break;
                    }
                    String request = scanner.next();
                    String response = process(request);
                    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 {
            try {
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

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

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

客户端代码写完以后,就需要实现客户端的代码

image-20220528171913227

构造方法中的IP地址和端口号是要建立连接的服务器的ip地址和端口号

image-20220528172248839

使用两个try() 和InputStream,OutputStream 用接受和发送客户端的数据流给服务器

操作步骤一

从控制台获取到要用户输入的字符串并且发送给服务器

image-20220528172627990

操作步骤二

从服务器获取响应,并且将结果显示在控制台上

image-20220528173003771

TcpEchoclient客户端

public class TcpEchoClient {
    private Socket socket = null;

    public TcpEchoClient(String serverIP,int serverPort) throws IOException {
        socket = new Socket(serverIP,serverPort);
    }
    public void start(){
        System.out.println("服务器连接成功");
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream()){
            try (OutputStream outputStream = socket.getOutputStream()){
                while (true) {
                    System.out.print("->");
                    String request = scanner.next();
                    PrintWriter printWriter = new PrintWriter(outputStream);
                    printWriter.println(request);
                    printWriter.flush();

                    Scanner respScanner = new Scanner(inputStream);
                    String response = respScanner.next();
                    System.out.printf("req: %s, resp: %s\n", request, response);
                }
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

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

上述的代码,一个服务器只能接收一个客户端的请求.一个服务器不应该只可以处理一个客户端,所以我们需要对代码进行改进.实现多线程

能够和客户端进行交互的前提就是要先调用accept,接收连接,

image-20220410123346792

原因就是第二次连接的时候,第一次的accept并没有断开连接,所以客户端和服务器并不是再次进行连接,也就无法实现多线程

为服务器加入多线程.

方法一:

每次连接连接之后,就进入一个线程,这样就可以实现多线程

image-20220528175823619

image-20220528175907606

方法二:使用线程池:

image-20220528180056579

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值