广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java基于TCP协议的Socket通信
  • 711
分享到

Java基于TCP协议的Socket通信

2024-04-02 19:04:59 711人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录简介tcp简介JAVA Socket简介SocketImpl介绍TCP 编程构造ServerSocket1.1 绑定端口1.2 设定客户连接请求队列的长度1.3 设定绑定的IP

简介

TCP简介

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据报协议(UDP,下一篇博客会实现)是同一层内 另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。

应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元( MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。

JAVA Socket简介

所谓socket 通常也称作”套接字“,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过”套接字”向网络发出请求或者应答网络请求

以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。

重要的Socket api

java.net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,其它方法大家可以见jdk-1.3文档。

  • . Accept方法用于产生”阻塞”,直到接受到一个连接,并且返回一个客户端的Socket对象实例。”阻塞”是一个术语,它使程序运行暂时”停留”在这个地方,直到一个会话产生,然后程序继续;通常”阻塞”是由循环产生的。
  • . getInputStream方法获得网络连接输入,同时返回一个InputStream对象实例。
  • . getOutputStream方法连接的另一端将得到输入,同时返回一个OutputStream对象实例。

注意:其中getInputStream和getOutputStream方法均会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用。

SocketImpl介绍

既然不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的,那么当然要介绍啦。

抽象类 SocketImpl 是实际实现套接字的所有类的通用超类。创建客户端和服务器套接字都可以使用它。

具体JDK见:

https://www.jb51.net/softs/214120.html

由于它是超类具体代码实现还是见下面的Socket

TCP 编程

构造ServerSocket

具体API见:Https://www.jb51.net/article/232094.htm

构造方法:

  • ServerSocket() ~创建非绑定服务器套接字。
  • ServerSocket(int port) ~创建绑定到特定端口的服务器套接字。
  • ServerSocket(int port, int backlog) ~利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
  • ServerSocket(int port, int backlog, InetAddress bindAddr) ~使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。

1.1 绑定端口

除了第一个不带参数的构造方法以外, 其他构造方法都会使服务器与特定端口绑定, 该端口有参数 port 指定. 例如, 以下代码创建了一个与 80 端口绑定的服务器:


ServerSocket serverSocket = new ServerSocket(80);

如果运行时无法绑定到 80 端口, 以上代码会抛出 IOException, 更确切地说, 是抛出 BindException, 它是 IOException 的子类. BindException 一般是由以下原因造成的:

  • 端口已经被其他服务器进程占用;
  • 在某些操作系统中, 如果没有以超级用户的身份来运行服务器程序, 那么操作系统不允许服务器绑定到 1-1023 之间的端口.

如果把参数 port 设为 0, 表示由操作系统来为服务器分配一个任意可用的端口. 有操作系统分配的端口也称为匿名端口. 对于多数服务器, 会使用明确的端口, 而不会使用匿名端口, 因为客户程序需要事先知道服务器的端口, 才能方便地访问服务器.

1.2 设定客户连接请求队列的长度

当服务器进程运行时, 可能会同时监听到多个客户的连接请求. 例如, 每当一个客户进程执行以下代码:


Socket socket = new Socket("www.javathinker.org", 80); 

就意味着在远程 www.javathinker.org 主机的 80 端口上, 监听到了一个客户的连接请求. 管理客户连接请求的任务是由操作系统来完成的. 操作系统把这些连接请求存储在一个先进先出的队列中. 许多操作系统限定了队列的最大长度, 一般为 50 . 当队列中的连接请求达到了队列的最大容量时, 服务器进程所在的主机会拒绝新的连接请求. 只有当服务器进程通过 ServerSocket 的 accept() 方法从队列中取出连接请求, 使队列腾出空位时, 队列才能继续加入新的连接请求.

对于客户进程, 如果它发出的连接请求被加入到服务器的请求连接队列中, 就意味着客户与服务器的连接建立成功, 客户进程从 Socket 构造方法中正常返回. 如果客户进程发出的连接请求被服务器拒绝, Socket 构造方法就会抛出 ConnectionException.

Tips: 创建绑定端口的服务器进程后, 当客户进程的 Socket构造方法返回成功, 表示客户进程的连接请求被加入到服务器进程的请求连接队列中. 虽然客户端成功返回 Socket对象, 但是还没跟服务器进程形成一条通信线路. 必须在服务器进程通过 ServerSocket 的 accept() 方法从请求连接队列中取出连接请求, 并返回一个Socket 对象后, 服务器进程这个Socket 对象才与客户端的 Socket 对象形成一条通信线路.

ServerSocket 构造方法的 backlog 参数用来显式设置连接请求队列的长度, 它将覆盖操作系统限定的队列的最大长度. 值得注意的是, 在以下几种情况中, 仍然会采用操作系统限定的队列的最大长度:

  • backlog 参数的值大于操作系统限定的队列的最大长度;
  • backlog 参数的值小于或等于0;
  • 在ServerSocket 构造方法中没有设置 backlog 参数.

以下的 Client.java 和 Server.java 用来演示服务器的连接请求队列的特性.

Client.java


import java.net.Socket;
public class Client {
 public static void main(String[] args) throws Exception{
  final int length = 100;
  String host = "localhost";
  int port = 1122;
  Socket[] socket = new Socket[length];
  for(int i = 0;i<length;i++){
   socket[i] = new Socket(host,port);
   System.out.println("第"+(i+1)+"次连接成功!");
  }
  Thread.sleep(3000);
  for(int i=0;i<length;i++){
   socket[i].close();
  }
 }
}

Server.java


import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
 private int port = 1122;
 private ServerSocket serverSocket;

 public Server() throws Exception{
  serverSocket = new ServerSocket(port,3);
  System.out.println("服务器启动!");
 }
 public void service(){
  while(true){
   Socket socket = null;
   try {
    socket = serverSocket.accept();
    System.out.println("New connection accepted "+
      socket.getInetAddress()+":"+socket.getPort());
   } catch (IOException e) {
    e.printStackTrace();
   }finally{
    if(socket!=null){
     try {
      socket.close();
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
   }
  }
 }

 public static void main(String[] args) throws Exception{
  Server server = new Server();
  Thread.sleep(60000*10);
  server.service();
 }
}

Client 试图与 Server 进行 100 次连接. 在 Server 类中, 把连接请求队列的长度设为 3. 这意味着当队列中有了 3 个连接请求时, 如果Client 再请求连接, 就会被 Server 拒绝.  下面按照以下步骤运行 Server 和 Client 程序.

⑴ 在Server 中只创建一个 ServerSocket 对象, 在构造方法中指定监听的端口为1122 和 连接请求队列的长度为 3 . 构造 Server 对象后, Server 程序睡眠 10 分钟, 并且在 Server 中不执行 serverSocket.accept() 方法. 这意味着队列中的连接请求永远不会被取出. 运行Server 程序和 Client 程序后, Client程序的打印结果如下:
第 1 次连接成功
第 2 次连接成功
第 3 次连接成功
Exception in thread “main” java.net.ConnectException: Connection refused: connect
…………….
从以上打印的结果可以看出, Client 与 Server 在成功地建立了3 个连接后, 就无法再创建其余的连接了, 因为服务器的队已经满了.
⑵ 在Server中构造一个跟 ⑴ 相同的 ServerSocket对象, Server程序不睡眠, 在一个 while 循环中不断执行 serverSocket.accept()方法, 该方法从队列中取出连接请求, 使得队列能及时腾出空位, 以容纳新的连接请求. Client 程序的打印结果如下:
第 1 次连接成功
第 2 次连接成功
第 3 次连接成功
………..
第 100 次连接成功
从以上打印结果可以看出, 此时 Client 能顺利与 Server 建立 100 次连接.(每次while的循环要够快才行, 如果太慢, 从队列取连接请求的速度比放连接请求的速度慢的话, 不一定都能成功连接)

1.3 设定绑定的IP 地址

如果主机只有一个IP 地址, 那么默认情况下, 服务器程序就与该IP 地址绑定. ServerSocket 的第 4 个构造方法 ServerSocket(int port, int backlog, InetAddress bingAddr) 有一个 bindAddr 参数, 它显式指定服务器要绑定的IP 地址, 该构造方法适用于具有多个IP 地址的主机. 假定一个主机有两个网卡, 一个网卡用于连接到 Internet, IP为 222.67.5.94, 还有一个网卡用于连接到本地局域网, IP 地址为 192.168.3.4. 如果服务器仅仅被本地局域网中的客户访问, 那么可以按如下方式创建 ServerSocket:


ServerSocket serverSocket = new ServerSocket(8000, 10, InetAddress.getByName(“192.168.3.4”));

1.4 默认构造方法的作用

ServerSocket 有一个不带参数的默认构造方法. 通过该方法创建的 ServerSocket 不与任何端口绑定, 接下来还需要通过 bind() 方法与特定端口绑定.

这个默认构造方法的用途是, 允许服务器在绑定到特定端口之前, 先设置ServerSocket 的一些选项. 因为一旦服务器与特定端口绑定, 有些选项就不能再改变了.比如:SO_REUSEADDR 选项

在以下代码中, 先把 ServerSocket 的 SO_REUSEADDR 选项设为 true, 然后再把它与 8000 端口绑定:


ServerSocket serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true); //设置 ServerSocket 的选项
serverSocket.bind(new InetSocketAddress(8000));  //与8000端口绑定

如果把以上程序代码改为:


ServerSocket serverSocket = new ServerSocket(8000);
serverSocket.setReuseAddress(true);//设置 ServerSocket 的选项

那么 serverSocket.setReuseAddress(true) 方法就不起任何作用了, 因为 SO_REUSEADDR 选项必须在服务器绑定端口之前设置才有效.

线程示例

客户端:


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;


public class Client {
    public static void main(String[] args) {
        try {
            //1.创建客户端Socket,指定服务器地址和端口
            Socket socket=new Socket("localhost", 8888);
            //2.获取输出流,向服务器端发送信息
            OutputStream os=socket.getOutputStream();//字节输出流
            PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流
            pw.write("用户名:whf;密码:789");
            pw.flush();
            socket.shutdownOutput();//关闭输出流
            //3.获取输入流,并读取服务器端的响应信息
            InputStream is=socket.getInputStream();
            BufferedReader br=new BufferedReader(new InputStreamReader(is));
            String info=null;
            while((info=br.readLine())!=null){
                System.out.println("我是客户端,服务器说:"+info);
            }
            //4.关闭资源
            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务器:


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;


public class Server {
    public static void main(String[] args) {
        try {
            //1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
            ServerSocket serverSocket=new ServerSocket(8888);
            Socket socket=null;
            //记录客户端的数量
            int count=0;
            System.out.println("***服务器即将启动,等待客户端的连接***");
            //循环监听等待客户端的连接
            while(true){
                //调用accept()方法开始监听,等待客户端的连接
                socket=serverSocket.accept();
                //创建一个新的线程
                ServerThread serverThread=new ServerThread(socket);
                //启动线程
                serverThread.start();

                count++;//统计客户端的数量
                System.out.println("客户端的数量:"+count);
                InetAddress address=socket.getInetAddress();
                System.out.println("当前客户端的IP:"+address.getHostAddress());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务器处理类:


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;


public class ServerThread extends Thread {
    // 和本线程相关的Socket
    Socket socket = null;

    public ServerThread(Socket socket) {
        this.socket = socket;
    }

    //线程执行的操作,响应客户端的请求
    public void run(){
        InputStream is=null;
        InputStreamReader isr=null;
        BufferedReader br=null;
        OutputStream os=null;
        PrintWriter pw=null;
        try {
            //获取输入流,并读取客户端信息
            is = socket.getInputStream();
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
            String info=null;
            while((info=br.readLine())!=null){//循环读取客户端的信息
                System.out.println("我是服务器,客户端说:"+info);
            }
            socket.shutdownInput();//关闭输入流
            //获取输出流,响应客户端的请求
            os = socket.getOutputStream();
            pw = new PrintWriter(os);
            pw.write("欢迎您!");
            pw.flush();//调用flush()方法将缓冲输出
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            //关闭资源
            try {
                if(pw!=null)
                    pw.close();
                if(os!=null)
                    os.close();
                if(br!=null)
                    br.close();
                if(isr!=null)
                    isr.close();
                if(is!=null)
                    is.close();
                if(socket!=null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

以上所述是小编给大家介绍的Java基于TCP协议的Socket通信,希望对大家有所帮助。在此也非常感谢大家对编程网网站的支持!

--结束END--

本文标题: Java基于TCP协议的Socket通信

本文链接: https://www.lsjlt.com/news/160072.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java基于TCP协议的Socket通信
    目录简介TCP简介JAVA Socket简介SocketImpl介绍TCP 编程构造ServerSocket1.1 绑定端口1.2 设定客户连接请求队列的长度1.3 设定绑定的IP ...
    99+
    2022-11-12
  • Python 基于TCP 传输协议的网络通信实现方法
    目录1、基础概念1.1 协议1.2 IP 地址1.3 端口2、TCP 网络编程实现2.1 服务器端编程2.2 客户端编程3 总结1、基础概念 什么是网络编程? 指在网络环境中,如何实...
    99+
    2022-11-13
  • Java网络编程之基于TCP协议
    目录一、单向通信二、双向通信三、对象流传送四、加入完整的处理异常方式五、多线程接收用户请求一、单向通信 功能:客户端发送一句话到服务器: 客户端: public class ...
    99+
    2022-11-12
  • 基于BIO的Java Socket通信详解
    BIO,即阻塞IO,在基于Socket的消息通信过程中,Socket服务端向外部提供服务,而Socket客户端可以建立到Socket服务端的连接,进而发送请求数据,然后等待Socket服务端处理,并返回处理结果(响应)。基于BIO的通信,S...
    99+
    2023-05-30
    bio java socket
  • C#基于Socket的TCP通信实现聊天室案例
    本文实例为大家分享了C#基于Socket的TCP通信实现聊天室的具体代码,供大家参考,具体内容如下 一、Socket(套接字)通信概念 套接字(socket)是通信的基石,用于描述I...
    99+
    2022-11-13
  • java如何利用socket通信实现Modbus-RTU通信协议
    小编给大家分享一下java如何利用socket通信实现Modbus-RTU通信协议,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!ModbusModbus是一种串行...
    99+
    2023-06-14
  • Java实现基于UDP协议的网络通信UDP编程
    目录UDP编程通信基本介绍基本流程UDP编程通信 基本介绍 类DatagramSocket和DatagramPacket【数据包/数据报】实现了基于UDP协议网络程序。UDP数据报通...
    99+
    2023-05-17
    Java UDP编程 Java UDP网络编程
  • java利用socket通信实现Modbus-RTU通信协议的示例代码
    Modbus Modbus是一种串行通信协议。Modbus 一个工业上常用的通讯协议、一种通讯约定。Modbus协议包括RTU、ASCII、TCP。其中MODBUS-RTU最常用,...
    99+
    2022-11-12
  • 如何使用C#基于Socket的TCP通信实现聊天室
    这篇文章给大家分享的是有关如何使用C#基于Socket的TCP通信实现聊天室的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。具体内容如下一.Socket(套接字)通信概念套接字(socket)是通信的基石,用于描述...
    99+
    2023-06-29
  • 基于Qt的TCP实现通信
    本文实例为大家分享了基于Qt的TCP实现通信的具体代码,供大家参考,具体内容如下 一、tcp介绍 TCP是面向连接的可靠传输的协议,协议规定通信的双方是服务端和客户端的两个角色:服务...
    99+
    2022-11-13
  • Python基于socket实现TCP/IP客户和服务器通信
    目录前言简单的搭建服务器与客户端服务器客户端create_connection(更简易的客户端)前言 套接字除了用于分析网络地址等功能之外,还可以配置一个服务器,监听到来的消息。 比如你在网络上跟网络机器人聊天,你发...
    99+
    2022-06-02
    Python 客户和服务器通信 Python TCP/IP 通信
  • .NET编程——利用C#实现TCP协议的异步通信Socket套接字(WinForm)
    本文将介绍利用基于TCP通信协议的Socket实现服务器与客户端之间的数据传输。 目录 前言 计算机通信 创建服务器 服务器通信 创建客户端 客户端通信 前言         TCP/IP(Transmission Control Pr...
    99+
    2023-09-04
    tcp/ip c# mysql 服务器
  • Python基于socket如何实现TCP/IP客户和服务器通信
    这篇文章主要为大家展示了“Python基于socket如何实现TCP/IP客户和服务器通信”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Python基于socket如何实现TCP/IP客户和服务...
    99+
    2023-06-15
  • 基于隐私保护技术的DNS通信协议介绍
    本文提出了一种基于用户数据报协议的DNS传输中用户隐私保护的加密方法:DNSDEA。该方法采用PKI加密体系与DNS协议相融合,不仅解决了域名隐私保护问题,而且与传统DNS体系相兼容,保持了DNS系统的简单、高效的技术特点。域名系统(DNS...
    99+
    2023-06-04
  • Java后端学习精华之TCP通信传输协议详解
    目录Socket连接模型消息协议传输过程中数据类型需要了解的细节TCP通信代码上篇教程回顾 ServerSocket --监听客户端的连接,他的作用主要是建立一个连接 -Serve...
    99+
    2022-11-12
  • 基于QT的TCP通信服务的实现
    目录一、结构1.1 套接字1.2 socket通信流程1.3 QTcpsocket1.4 QTcpServer二、设计UI2.1 客户端UI2.2 服务器端UI三、核心代码四、效果图...
    99+
    2022-11-13
  • Java基于UDP协议的聊天室功能
    UDP简述 UDP(User Datagram Protocol)协议是Internet 协议集支持的一个无连接的传输协议,中文名为用户数据报协议。它为应用程序提供了一种无需建立连接...
    99+
    2022-11-13
  • 怎么基于Kotlin实现一个简单的TCP自定义协议
    这篇文章主要讲解了“怎么基于Kotlin实现一个简单的TCP自定义协议”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么基于Kotlin实现一个简单的TCP...
    99+
    2022-10-19
  • C#基于Socket套接字的网络通信封装
    本文为大家分享了C#基于Socket套接字的网络通信封装代码,供大家参考,具体内容如下 摘要 之所以要进行Socket套接字通信库封装,主要是直接使用套接字进行网络通信编程相对复杂,...
    99+
    2022-11-12
  • C#基于Socket的网络通信类你了解吗
    目录摘要代码总结摘要 之所以要进行Socket套接字通信库封装,主要是直接使用套接字进行网络通信编程相对复杂,特别对于初学者而言。实际上微软从.net 2.0开始已经提供了TCP、U...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作