【Java】网络编程

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

Socket套接字

概念

Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基
于Socket套接字的网络程序开发就是网络编程

分类

  1. 流套接字:使用传输层TCP协议

特点
有连接,可靠传输,面向字节流,有接收缓冲区也有发送缓冲区,大小不限

对于字节流来说,可以简单的理解为,传输数据是基于IO流,流式数据的特征就是在IO流没有关闭的情
况下,是无边界的数据,可以多次发送,也可以分开多次接收。

  1. 数据报套接字:使用传输层UDP协议
    UDP,即User Datagram Protocol(用户数据报协议),传输层协议。

特点
无连接,不可靠传输,面向数据报,有接收缓冲区,无发送缓冲区,大小受限,一次最多64k

对于数据报来说,可以简单的理解为,传输数据是一块一块的,发送一块数据假如100个字节,必须一
次发送,接收也必须一次接收100个字节,而不能分100次,每次接收1个字节。

Java数据报套接字通信模型

对于UDP协议来说,具有无连接,面向数据报的特征,即每次都是没有建立连接,并且一次发送全部数
据报,一次接收全部的数据报。

java中使用UDP协议通信,主要基于 DatagramSocket 类来创建数据报套接字,并使用
DatagramPacket 作为发送或接收的UDP数据报。

一次发送和接受UDP数据报

一次UDP数据报的发送区分发送端和接收端
发送端

第一步先创建DatagramSocket ,然后构造出要发送的内容,放在DatagramPacket数据报中(包含发送的数据,和ip地址,端口号等信息)
第二步发送数据包给接受端,通过socket.send()方法来发送给接收端
第三步接收端创建DatagramSocket,通过DatagramPacket构造出一个存放数据报的空间,通过socket.receive()方法来接受一个UDP数据报,
最后接收端获取到了发送端发送的信息

以上只是一次发送端的UDP数据报发送,及接收端的数据报接收,并没有返回的数据。也就是只有请求,没有响应。对于一个服务端来说,重要的是提供多个客户端的请求处理及响应

提供多个客户端的请求处理及响应

对于请求响应模型,客户端和服务器同时担任接收端和发送端的任务
客户端先给服务器发送请求,服务器接收到请求后执行业务逻辑,构造响应再次发送给客户端,客户端再接收响应

Java流套接字通信模型

【Java】网络编程,网络,Java,java,网络,开发语言

Socket编程注意事项

  1. 客户端和服务端:开发时,经常是基于一个主机开启两个进程作为客户端和服务端,但真实的场
    景,一般都是不同主机。
  2. 注意目的IP和目的端口号,标识了一次数据传输时要发送数据的终点主机和进程
  3. Socket编程我们是使用流套接字和数据报套接字,基于传输层的TCP或UDP协议,但应用层协议,
    也需要考虑,这块我们在后续来说明如何设计应用层协议

UDP数据报套接字编程

DatagramSocket API

DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。

构造方法

方法名 方法说明
DatagramSocket() 创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket(intport) 创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)

普通方法

方法名 方法说明
voidreceive(DatagramPacket p) 从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacketp) 从此套接字发送数据报包(不会阻塞等待,直接发送)
void close() 关闭此数据报套接字

DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报。

构造方法

方法 方法说明
DatagramPacket(byte[] buf, int length) 构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[]buf, int offset, int length,SocketAddress address) 构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

普通方法

方法名 方法说明
InetAddress getAddress() 从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort() 从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData() 获取数据报中的数据

构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。

InetSocketAddress API

InetSocketAddress SocketAddress 的子类 )构造方法:

InetSocketAddress(InetAddress addr, int port) 创建一个Socket地址,包含IP地址和端口号

实现回显UDP客户端和服务器

客户端

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;
    public UdpEchoClient(String ip, int port) throws SocketException {
        serverIp = ip;
        serverPort = port;
        //客户端端口号让系统自动分配
        socket = new DatagramSocket();
    }
    //让客户端反复从控制台读取用户输入的数据,把输入的数据构造成UDP请求,发送给服务器
    //在读取服务器返回的响应,打印到控制台
    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("客户端启动");
        while (true){
            //1.从控制台获取用户输入的数据
            System.out.print("-->");
            String request = scanner.next();
            //构造出请求对象,发送给服务器
            /**
             * 第一个参数是数据转换为字节数组
             * 第二个参数是字节数组的长度
             * 第三个参数是ip地址
             * 第四个参数是端口号
             */
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);
            //发送给服务器
            socket.send(requestPacket);
            //等待服务器返回响应数据报
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            //将数据报中的数据构造成字符串打印在控制台上
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);
        }
    }

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

服务器

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * UDP回显服务器
 */
public class UdpEchoServer {
    private DatagramSocket socket = null;

    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

    //启动服务器
    public void start() throws IOException {
        System.out.println("服务器启动");
        while (true) {
            //1.读取客户端发来的请求
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            //2.根据请求,做出响应
            String response = process(request);
            //这里是回显服务器,就返回客户端发来的请求
            DatagramPacket responsePocket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getAddress(),requestPacket.getPort());
            socket.send(responsePocket);
            System.out.printf("[%s,%d] req: %s,resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),
                    request,response);
        }
    }

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

    public static void main(String[] args) throws IOException {
        UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
        udpEchoServer.start();

    }
}

【Java】网络编程,网络,Java,java,网络,开发语言
【Java】网络编程,网络,Java,java,网络,开发语言
【Java】网络编程,网络,Java,java,网络,开发语言
【Java】网络编程,网络,Java,java,网络,开发语言
服务器能够进行一对多的响应

TCP流套接字编程

ServerSocket API

ServerSocket 是创建TCP服务端Socket的API

构造方法

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

普通方法

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

Socket API

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

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

构造方法

Socket(String host, int port)

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

普通方法

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

TCP中的长短连接

TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:

短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。

对比以上长短连接,两者区别如下:

  1. 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
  2. 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
  3. 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。

扩展了解:
基于BIO(同步阻塞IO)的长连接会一直占用系统资源。对于并发要求很高的服务端系统来说,这样的消耗是不能承受的。

由于每个连接都需要不停的阻塞等待接收数据,所以每个连接都会在一个线程中运行。
一次阻塞等待对应着一次请求、响应,不停处理也就是长连接的特性:一直不关闭连接,不停的处理请求。

实际应用时,服务端一般是基于NIO(即同步非阻塞IO)来实现长连接,性能可以极大的提升。

实现回显TCP客户端和服务器

服务器

import javafx.scene.layout.Priority;

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

public class TcpEchoServer {
    private ServerSocket serverSocket = null;
    //线程数目不固定的线程池
    private ExecutorService service = Executors.newCachedThreadPool();
    public TcpEchoServer(int port) throws IOException {
        //绑定端口号
        serverSocket = new ServerSocket(port);
    }
    //启动服务器
    public void start() throws IOException {
        System.out.println("服务器启动");
        while (true){
            Socket clientSocket = serverSocket.accept();
            //创建一个新的线程来完成任务
            //主线程用来接收客户端的连接
            //这里使用线程池,每有一个客户端请求,就使用一个线程
            service.submit(new Runnable() {
                @Override
                public void run() {
                    processConnection(clientSocket);
                }
            });
        }
    }
    private void processConnection(Socket clientSocket) {
        System.out.printf("[%s:%d] 客户端上线\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
        //socket对象内部包含了两个字节流对象,可以把这两个字节流对象获取到,完成读写操作
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            while (true) {
                //1.读取请求并解析
                //为了读取方便,使用scanner将流对象封装
                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封装OutputStream
                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) {
            throw new RuntimeException(e);
        }finally {
            //finally中加上close操作,保证socket被关闭

            try {
                clientSocket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

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

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

客户端文章来源地址https://www.toymoban.com/news/detail-695329.html

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 {
    private Socket socket = null;
    //构造方法和服务器建立连接
    public TcpEchoClient(String serverIp, int serverPort) throws IOException {
        //new操作结束后,就和服务器建立了连接
        socket = new Socket(serverIp,serverPort);
    }

    public void start(){
        System.out.println("客户端启动");
        Scanner scannerConsole = new Scanner(System.in);

        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()){
            while (true){
                System.out.print("-->");
                //1.控制台输入字符串
                String request = scannerConsole.next();
                //2.发送给服务器
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                printWriter.flush();
                //3.从服务器获取响应
                Scanner scanner = new Scanner(inputStream);
                String response = scanner.next();
                System.out.println(response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

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

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

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

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

相关文章

  • 计算机网络技术与JAVA网络编程URL编程-----JAVA入门基础教程-----计算机网络经典

    import org.junit.jupiter.api.Test; import java.io.*; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class URLTest { public static void main(String[] args) { //URL:统一资源定位符(种子),一个URL就定位着互联网上某个资源的地址 //http:应用层协议,IP地址,端口号,资源地址,参数

    2024年02月15日
    浏览(57)
  • 计算机网络技术与JAVA网络编程UDP编程-----JAVA入门基础教程-----计算机网络经典

    import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.*; public class UDP { public static void main(String[] args) { DatagramSocket datagramSocket = null; try { datagramSocket = new DatagramSocket(); InetAddress inetAddress = InetAddress.getByName(\\\"127.0.0.1\\\"); int port = 9090; byte[] byte

    2024年02月15日
    浏览(49)
  • Java 网络编程 —— 非阻塞式编程

    在生活中,最常见的阻塞现象是公路上汽车的堵塞。汽车在公路上快速行驶,如果前方交通受阻,就只好停下来等待,等到公路顺畅,才能恢复行驶。 线程在运行中也会因为某些原因而阻塞。所有处于阻塞状态的线程的共同特征:放弃 CPU,暂停运行,只有等到导致阻塞的原

    2024年02月04日
    浏览(49)
  • Java网络编程(一)基本网络概念

            网络(network) 是几乎可以实时相互发送和接收数据的计算机和其他设备的集合。网络通常用线缆连接,数据位转换为电磁波,通过线缆移动。不过,无线网络会通过无线电波传输数据,许多长距离的传输现在会用通过玻璃纤维发送可见光的光纤电缆来完成。传输数

    2024年02月16日
    浏览(42)
  • Java 网络编程 —— 安全网络通信

    SSL(Secure Socket Layer,安全套接字层)是一种保证网络上的两个节点进行安全通信的协议。IETF(Interet Engineering Task Force)国际组织对 SSL 作了标准化,制定了 RFC2246 规范,并将其称为传输层安全(Transport Layer Security,TLS) SSL 和 TLS 都建立在 TCP/IP 的基础上,一些应用层协议,如

    2024年02月11日
    浏览(38)
  • Java——网络编程

    InetAddress类 java.net.InetAddress类用来封装计算机的IP地址和DNS(没有端口信息),它包括一个主机名和一个ip地址,是java对IP地址的高层表示。大多数其他网络类都要用到这个类,包括Sorket、ServerSocker、URL、DatagramSorket、DatagramPacket等 常用静态方法 getLocalHost()得到本机的InetAddress对象,其

    2024年03月16日
    浏览(37)
  • JAVA网络编程(一)

    定义 :在网络通信协议下,不同计算机上运行的程序,进行的数据传输。 应用场景 :即时通信,网游,邮件等 不管什么场景,都是计算机与计算机之间通过网络在进行数据传输 java提供一个java.net包,可以帮助我们开发网络应用程序。 CS架构是指在远端有一个服务器Server,

    2024年02月07日
    浏览(33)
  • Java网络编程知识

    目录 1.网络编程概述 1.网络编程的目的 2.网络编程的三个问题 1.如何准确定位网络上的主机? 2.如何定位主机上的特定应用? 3.找到主机后如何可靠高效的进行数据传输? 2.通信要素一:IP和端口号 1.IP地址 2.端口号 3.套接字 3.通信要素二:网络协议 1.使用TCP协议通信 1.客户端

    2024年02月08日
    浏览(41)
  • 【Java】网络编程

    Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基 于Socket套接字的网络程序开发就是网络编程 流套接字 : 使用传输层TCP协议 特点 有连接,可靠传输,面向字节流,有接收缓冲区也有发送缓冲区,大小不限 对于字节流来说,可以简单

    2024年02月10日
    浏览(33)
  • Java的网络编程

    两台设备之间通过网络实现数据传输,将数据通过网络从一台设备传输到另一台设备 网络 两台或多台设备通过一定物理设备连接起来构成了网络 网络又分为: 局域网:覆盖范围最小,仅仅覆盖一个教室或一个机房 城域网:覆盖范围较大,可以覆盖一个城市 广域网:覆盖范围最大

    2024年02月12日
    浏览(35)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包