网络编程套接字之三tcp(代码片段)

快到锅里来呀 快到锅里来呀     2023-03-31     550

关键词:

目录

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?

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

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

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

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

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

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

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

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

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构造的区别,有连接和无连接 

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. 运行回显服务器和客户端

 

 

python网络编程—socket套接字编程(tcp)(代码片段)

套接字介绍1.套接字:实现网络编程进行数据传输的一种技术手段2.Python实现套接字编程:importsocket3.套接字分类流式套接字(SOCK_STREAM):以字节流方式传输数据,实现tcp网络传输方案。(面向连接--tcp协议--可靠的--流式套接字)数据... 查看详情

网络linuxlinux网络编程-tcp,udp套接字编程及代码示范(代码片段)

这里写目录标题UDP类UDP服务端单执行流UDP客户端TCP类TCP单执行流服务器TCP客户端TCP多执行流(线程)TCP多执行流(进程)本文我们分为TCP和UDP协议网络程序的编写:他们的区别如下:项目特点UDP用户数据报协议,无需连接&#... 查看详情

网络编程套接字(tcp)(代码片段)

目录1、实现一个TCP网络程序(单进程版)        1.1、服务端serverTcp.cc文件                 服务端创建套接字                 服务端绑定                 服务端监听               ... 查看详情

tcp套接字编程常用函数(代码片段)

...h>intsocket(intfamily,inttype,intprotocol);//调用成功返回非负的套接字描述符,出错返回-1connect函数TCP客户端用connect函数来建立与TCP服务器的连接#include<sys/socket.h 查看详情

tcp的网络编程基础(代码片段)

        服务器建立ServerSocket对象ServerSocket对象负责等待客户端请求建立套接字连接,类似邮局某个窗口中的业务员。也就是说,服务器必须事先建立一个等待客户请求建立套接字的连接的ServerSocket... 查看详情

c_cpplinux的下tcp的套接字编程示例(代码片段)

查看详情

网络编程tcp网络应用程序开发(代码片段)

【网络编程】TCP网络应用程序开发TCP网络应用程序开发流程1.TCP网络应用程序开发流程的介绍2.TCP客户端程序开发流程的介绍3.TCP服务端程序开发流程的介绍4.小结TCP客户端程序开发1.开发TCP客户端程序开发步骤回顾2.socket类的介绍... 查看详情

python网络编程—tcp套接字之http传输(代码片段)

HTTP协议(超文本传输协议) 1.用途:网页获取,数据的传输  2.特点: 应用层协议,传输层使用tcp传输简单,灵活,很多语言都有HTTP专门接口无状态,协议不记录传输内容http1.1支持持久连接,丰富了请求类型3.网... 查看详情

java网络编程-第四节:tcp流套接字(serversocket)编程(代码片段)

文章目录一:Java流套接字通信模型二:相关API详解(1)ServerSocket(2)Socket三:TCP通信示例一:客户端发送什么服务端就返回什么(1)代码(2)效果展示(3)分析四: 查看详情

java网络编程-第四节:tcp流套接字(serversocket)编程(代码片段)

文章目录一:Java流套接字通信模型二:相关API详解(1)ServerSocket(2)Socket三:TCP通信示例一:客户端发送什么服务端就返回什么(1)代码(2)效果展示(3)分析四: 查看详情

第4章基本tcp套接字编程(代码片段)

4.1各种套接字api(重要)4.1.1socket()用于创建一个套接字描述符,这个描述符指明的是tcp还是udp,同时还有ipv4还是ipv6#include<sys/socket.h>?intsocket(intfamily,inttype,intprotocol);//成功返回描述符,错误-1family主要是指明的协议族,AF_INET... 查看详情

socket编程-tcp(代码片段)

server.pyimportsocketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#第一个参数为套接字的地址家族AF_INET代表网络套接字,第二个参数SOCK_STREAM代表tcp协议phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)#当服务端关闭时,再重启服务端 查看详情

基本套接字编程--tcp篇(代码片段)

1.Socket简介Socket是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机的相关进程之间的数据交换。几个定义:(1)IP地址:即依照TCP/IP协议分配给本地主机的网络地址,两个进程要... 查看详情

套接字实现tcp服务器(代码片段)

套接字编程又被叫做是socket编程,socket这个词可以表示很多概念:在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址+端口号”就称为socket。在TCP协议中,建立连接的两个进程各自有一个socket... 查看详情

10.网络编程之socket(代码片段)

目录一、什么是socket?1.1套接字简介1.2套接字地址:主机-端口对二、面向连接的套接字和为无连接的套接字2.1面向连接的套接字2.2无连接的套接字三、python中socket3.1socket()模块函数3.2套接字对象(内置)方法3.3Socket中的一些参数四... 查看详情

网络编程-tcp(代码片段)

tc相当于打电话,需要先建立链接,区分客户端与服务端。importsocketdefmain():#1.创建tcp的套接字tcp_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#2.链接服务器#tcp_socket.connect(("192.168.33.11",7890))server_ip=input("请输入要链接的服务器的ip:")se... 查看详情

网络编程之tcp客户端开发和tcp服务端开发(代码片段)

开发TCP客户端程序开发步骤创建客户端套接字对象和服务端套接字建立连接发送数据接收数据关闭客户端套接字 importsocketif__name__==‘__main__‘:#创建tcp客户端套接字#1.AF_INET:表示ipv4#2.SOCK_STREAM:tcp传输协议tcp_client_socket=socket.so... 查看详情

tcp/ip网络编程习题2(代码片段)

1.什么是协议?在收发数据中定义协议有何意义?协议是对话中使用的通信规则.定义协议可让计算机进行正确无误的对话.2.面向连接的TCP套接字传输特性有3点,请分别说明?可靠性,传输的过程数据不会丢失字节流,按序传输数据... 查看详情