TCP协议常用API以及实现TCP客户端服务端

目录

TCP常用API

ServerSocket 

Socket 

TCP服务端(单线程) 

属性+构造方法:

代码编写 

TCP客户端(单线程) 

属性+构造方法 

代码编写 

单线程TCP客户端—服务端通信结果 

单线程TCP存在的问题 

TCP服务端(支持多个客户发送请求) 

多线程版本服务端 

线程池版本服务端   

关于TCP的长连接和短连接 

短连接工作过程 

长连接工作过程 


TCP常用API

ServerSocket:专门给服务端使用的socket。 

Socket:既可以提供给客户端使用,也可以给服务端使用。 

ServerSocket 

构造方法:

方法签名方法说明
ServerSocket(int port)创建一个服务端嵌套字,并且指定服务端所占用的进程

成员方法 accept: 

方法签名方法说明
Socket accept()

TCP是"有连接"的协议,TCP客户端与服务端一定要建立连接,才可以互相发送消息。因此这个accept方法,返回的socket对象,服务端就是通过这个socket对象和客户端进行通信的。

如果服务端没有收到socket对象,那么就会阻塞等待,无法进行通信。

Socket 

  对于服务端来说,是由accept()方法返回的的,返回的socket对象用于和客户端进行通信。 

构造方法 :

对客户端来说,构造方法构造对象时需要指定ip地址和端口号,这个ip和端口号是服务端的 

  

两个普通常用的方法: 

方法签名方法说明
getInputStream()通过socket对象,获取到内部的输入流对象
getOutputStream()通过socket对象,获取到内部的输出流对象

TCP服务端(单线程) 

属性+构造方法:

       需要在TcpEchoServer内部封装一个属性,这个属性是ServerSocket。

       在构造方法当中,需要指定ServerSocket占用哪个端口号,此端口号就是服务端的端口号

代码编写 

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;

public class TcpEchoServer {
    /**
     * 用于TCP客户端和服务端通信的socket对象
     */
    private ServerSocket serverSocket;

    /**
     * 构造方法指定服务端所占用的端口号
     */
    public TcpEchoServer(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }
    /**
     * 启动服务端
     */
    public void start() throws IOException {
        System.out.println("启动服务端!");
        while(true){
            //使用clientSocket与客户端交流
            Socket clientSocket=serverSocket.accept();//1、接收客户端发送的socket
            processConnection(clientSocket);//2、处理客户端的连接
        }
    }

    /**
     * 处理客户端发送来的连接
     * 客户端发送来的连接:clientSocket
     */
    public void processConnection(Socket clientSocket) throws IOException {

        //输出客户端ip地址和端口号
        System.out.println("客户端已上线!客户端的IP是:"+clientSocket.getInetAddress()+
                "客户端的端口号是:"+clientSocket.getPort());
        //2-1、读取clientSocket中的输入输出流对象
        InputStream inputStream=clientSocket.getInputStream();
        OutputStream outputStream=clientSocket.getOutputStream();
        //使用while循环处理多个请求和响应
        while (true){
            //2-2、通过Scanner来获取输入流
            Scanner scanner=new Scanner(inputStream);
            //读取完毕直接返回
            if(!scanner.hasNext()){
                System.out.println("客户端已经下线!客户端的IP是:"
                        +clientSocket.getInetAddress()+
                        ";客户端的端口是:"+clientSocket.getPort());
                //退出循环
                break;
            }
            //2-3、根据请求计算响应
            String request=scanner.next();
            //构造回写内容
            String response="服务器已经响应:"+request;
            //2-4、使用PrintWriter发送OutputStream
            PrintWriter printWriter=new PrintWriter(outputStream);
            printWriter.println(response);
            //刷新缓冲区保证能够发送出去
            printWriter.flush();
        }
        //2-5、关闭连接
        clientSocket.close();

    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer tcpEchoServer=new TcpEchoServer(9090);
        tcpEchoServer.start();//服务端启动
    }
}

TCP客户端(单线程) 

属性+构造方法 

需要在TcpEchoClient中加入Socket指定服务端的Ip地址和端口号

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

public class TcpEchoClient {
    //客户端属性socket指定服务端IP+端口号
    private Socket socket;
    public TcpEchoClient(String serverIp,int port) throws IOException {
        socket=new Socket(serverIp,port);
    }
    
}

TCP是有连接的,所以要想使客户端和服务端可以通信就需要先建立连接,这里的socket对象创建时就说明客户端和服务端成功建立了连接。 

客户端的socket创建完成的瞬间,服务端的accept方法就会立即接收到客户端的socket对象。 

代码编写 

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

public class TcpEchoClient {
    //客户端属性socket指定服务端IP+端口号
    private Socket socket;
    public TcpEchoClient(String serverIp,int port) throws IOException {
        socket=new Socket(serverIp,port);
    }
    //启动客户端
    public void start() throws IOException {
        System.out.println("客户端已上线!");
        //1、利用socket获取到与服务端进行数据交互的输入输出流(inputStream和outputStream)
        Scanner input=new Scanner(System.in);
        InputStream inputStream = socket.getInputStream();
        OutputStream outputStream=socket.getOutputStream();//都是相对于客户端来进行输入/输出操作的。
        while(true){
            //2、从控制台获取用户输入的信息
            System.out.println("输入你想要发送的信息:");
            String request=input.next();
            //3、将获取到的request通过流的方式发送给服务端
            PrintWriter printWriter=new PrintWriter(outputStream);
            printWriter.println(request);
            printWriter.flush();//刷新缓冲区
            //4、通过Scanner读取服务端响应并进行回显
            //读取服务端响应
            Scanner scanner=new Scanner(inputStream);
            String response=scanner.next();
            //响应内容回显到界面
            System.out.println(response);
        }
    }

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

}

单线程TCP客户端—服务端通信结果 

 

单线程TCP存在的问题 

当服务端启动之后,如果有客户端与服务端建立连接,服务端的accept方法就会返回一个socket对象,之后再通过processConnection方法对该客户端的socket不断进行while循环进行处理,调用scanner.next()方法,也就是说只要该客户端不下线,服务端就会一直在这个循环中,这将导致其他的想要建立连接的客户端无法完成。

当然,不使用while循环也是不可以的,因为如果没有while循环,客户端发送一次请求,服务端就会把连接给断掉,如果这个客户端还想继续建立连接,就需要重新建立连接,重新创建Socket对象,但是上述代码中的客户端只能创建一次socket,所以这时候就无法再建立连接了。

要想解决这个问题,就需要TCP服务端支持多线程进行操作。

TCP服务端(支持多个客户发送请求) 

支持多个客户发送请求用到多线程的知识,可以提供多线程版本的服务端和线程池版本的服务端

多线程版本服务端 

服务端的核心在于处理多个客户请求,也就是processConnection方法需要支持多线程,也就是说每个客户端的请求都会有一个线程进行处理。

多线程版本的服务端在客户端连接少的情况下是合适的,但是当客户端连接的量比较大的时候就不合适了,会有大量的线程的创建和销毁,资源耗费比较严重,所以可以考虑使用线程池来处理processConnection()方法。

线程池版本服务端   

 

关于TCP的长连接和短连接 

短连接工作过程 

1、客户端与服务端建立连接

2、客户端向服务端发送请求

3、读取响应

4、关闭连接 

特点:短连接一次通信一次连接,下一次通信需要重新建立连接,一次通信只会建立一次连接

长连接工作过程 

1、客户端与服务端建立连接

2、客户端向服务端发送请求

3、读取响应

4、可根据需求再次发送请求(也是回到2)

5、重复2-4之间若干次,再决定是否关闭连接 

特点:一次连接可多次发送请求,长连接的复用性更高 

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
大家知道,TCP/IP已成为计算机网络的事实上的标准。在关于TCP/IP的论著中,最有影响的就是两部著作。一部是Douglas E. Comer的《用TCP/IP进行网际互连》,而另一部就是Stevens写的这3卷书。这两套巨著都很有名,各有其特点。无论是从事计算机网络的教师还是进行科研的技术人员,这两套书都应当是必读的。   《TCP/IP详解,卷1:协议》是一本完整而详细的TCP/IP协议指南。描述了属于每一层的各个协议以及它们如何在不同操作系统中运行。作者用Lawrence Berkeley实验室的tcpdump程序来捕获不同操作系统和TCP/IP实现之间传输的不同分组。对tcpdump输出的研究可以帮助理解不同协议如何工作。本书适合作为计算机专业学生学习网络的教材和教师参考书。也适用于研究网络的技术人员。   《TCP/IP详解 卷2:实现》完整而详细地介绍了TCP/IP协议是如何实现的。书中给出了约500个图例,15 000行实际操作的C代码,采用举例教学的方法帮助你掌握TCP/IP实现。本书不仅说明了插口API协议族的关系以及主机实现与路由器实现的差别。还介绍了4.4BSD-Lite版的新的特点,如多播、长肥管道支持、窗口缩放、时间戳选项以及其他主题等等。读者阅读本书时,应当具备卷1中阐述的关于TCP/IP的基本知识。本书适用于希望理解TCP/TP协议如何实现的人,包括编写网络应用程序的程序员以及利用TCP/IP维护计算机网络的系统管理员。   《TCP-IP详解卷三TCP事务协议,HTTP,NNTP和UNIX域协议》是“TCP/IP详解系列”的延续。主要内容包括:TCP事务协议,即T/TCP,这是对TCP的扩展,使客户-服务器事务更快、更高效和更可靠;TCP/IP应用,主要是HTTP和NNTP;UNIX域协议,这些协议提供了进程之间通信的一种手段。当客户与服务器进程在同一台主机上时,UNIX域协议通常要比TCP/IP快一倍。本书同样采用了大量的实例和实现细节,并参考引用了卷2中的大量源程序。 本书适用于希望理解TCP/IP如何工作的人,包括编写网络应用程序的程序员以及利用TCP/IP维护计算机网络的系统管理员。
用c++/qt写的项目,可供自己学习,项目都经测试过,真实可靠,请放心使用。Qt支持 Windows、Linux/Unix、Mac OS X、Android、BlackBerry、QNX等多种平台,并为这些不同的平台提供了统一的开发环境。 面向对象 C++是完全面向对象的,这一点和Objective-c等在开发很相似。而Qt又是基于C++一种语言的扩展,大家都知道C++ 有快速、简易、面向对象等很多优点,所以Qt自然也继承者C++这些的优点。 Qt良好的封装机制使得Qt的模块化程度非常高,可重用性较好,对用户开发来货是非常方便的。Qt提供一种为signals/slots(信号和槽) 的安全类型来替代callback,使得各个元件之间的协同工作变得十分简单。 丰富的API Qt包括多达 250 个以上的 C++ 类,还提供基于模板的 collections, serialization, file, I/Odevice, directory management, date/time 类。甚至还包括正则表达式的处理功能。 支持 2D/3D 图形渲染,支持 OpenGL。 大量的开发文档。 XML支持 Webkit 引擎的集成,可以实现本地界面与Web内容的无缝集成, 但是真正使得 Qt 在自由软件界的众多 Widgets (如 Lesstif,Gtk,EZWGL,Xforms,fltk 等等)中脱颖而出的还是基于 Qt 的重量级软件 KDE。 信号和槽机制 Qt提供了信号和槽机制用于完成见面操作的响应,是完成任意两个Qt对象之通信机制。其中,信号会在某个特定情况或动作下被触动,槽是等同于接受并处理信号的函数。 为什么方法不是直接调用的。中间用到 Signal 和槽机制不是多此一举? 其实在我们生活也是一样,老板级别的好说话,老板给助理分派任务也好说话,但是助理给老板分任务,可想而知会有什么后果,在以前的统治阶层肯定不允许这样的事发生。所以在分层思想中,我们所调用的函数也是这样的,上层可以调用下层和同一层的函数,下层函数不可以调用上层函数,否则程序的层次性会被打破,导致结构错综复杂,难以维护和管理。 那么怎样才能做到向上管理呢,有任务分配给老板怎么办? 老板会设立一个机构,也就是一个函数,用无限循环来查询助理的状态,如果助理真的有事情,这个机构就把这消息拿到老板来处理。但是这种处理方式显得有些复杂,我们想要的简单明了的方式是,如果助理有事件发生,可以直接调用老板函数处理。 说了这么多其实就是想说,信号和槽的最大优势在于,它完善了程序分层的思想,可以在不改变程序的层次性的情况下,完成由下层到上层的调用。在下层发出一个 Signal,这时上层与其想关联的 Slot 函数就会响应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渴望力量的土狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值