Java入门系列-24-实现网络通信

简介:

互联网上那么多设备,java 是如何与其他设备通信的呢?这次的内容是网络通信的基础,有了它咱们才能上网页、玩游戏、视频聊天。

Socket 客户端套接字

Socket 客户端套接字,用于连接互联网提供服务的设备。

Socket 构造方法

构造方法 说明
Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字
Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号

常用方法

方法名称 说明
getOutputStream() 返回此套接字的输出流
getInputStream() 返回此套接字的输入流

下面示例模拟了一个 HTTP 请求

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

public class TestSocket {

    public static void main(String[] args) {
        
        //创建套接字
        try(Socket s=new Socket("www.baidu.com", 80);){
            //创建向服务器发送数据的输出流
            OutputStream os=s.getOutputStream();
            StringBuffer sb=new StringBuffer();
            //HTTP协议 请求报文
            sb.append("GET / HTTP/1.1\r\n");
            sb.append("Host: www.baidu.com:80\r\n");
            sb.append("Connection: Keep-Alive\r\n");
            //这里一定要一个回车换行,表示消息头完,不然服务器会等待
            sb.append("\r\n");
            //发送
            os.write(sb.toString().getBytes());
            //获取服务器相应内容 
            InputStream is=s.getInputStream();
            //通过输入流创建扫描器,并指定编码为utf-8防止中文乱码
            Scanner scanner=new Scanner(is,"utf-8");
            
            while(scanner.hasNextLine()) {
                String line=scanner.nextLine();
                System.out.println(line);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
            System.out.println("未知主机");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常");
        }
    }
}

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 TestServerSocket {

    public static void main(String[] args) {
        //创建 ServerSocket 监听1666端口
        try(ServerSocket server=new ServerSocket(1666)){
            //阻塞方法,当有客户端连入,获取客户端Socket
            try(Socket client=server.accept()){
                //获取客户端发送的数据
                InputStream is=client.getInputStream();
                //获取向客户端发送数据的流
                OutputStream os=client.getOutputStream();
                //通过输入流创建扫描器
                try(Scanner scanner=new Scanner(is)){
                    
                    PrintWriter pw=new PrintWriter(os,true/*自动刷新*/);
                    //向客户端发送消息
                    pw.println("Hello,enter bye to exit.");
                    boolean done=false;
                    //客户端有输入数据并且没有发送 bye 
                    while(!done&&scanner.hasNextLine()) {
                        //接收客户端发送的数据
                        String line=scanner.nextLine();
                        //将客户端发送的数据发回客户端
                        pw.println("Echo:"+line);
                        //如果客户端输入bye 结束通信
                        if(line.trim().equalsIgnoreCase("bye")) {done=true;}
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

测试方式:
在DOS 中输入命令:telnet 127.0.0.1 1666

telnet 不是内部或外部命令的读者,需要在 Windows 功能中启用 Telnet 客户端。

上面的代码如果有多个客户端连入就不行了,如果希望服务能被多个客户端连接,可以使用线程。

多线程服务器

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 TestMultiServerSocket {

    public static void main(String[] args) {
        //创建 ServerSocket 监听 1666端口
        try(ServerSocket server=new ServerSocket(1666)){
            while(true) {
                //accept() 是一个阻塞方法
                Socket client=server.accept();
                InputStream is=client.getInputStream();
                OutputStream os=client.getOutputStream();
                //开启新的线程处理,传入当前客户端
                Thread t=new Thread(new ThreadEchoHandler(client));
                t.start();                
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
class ThreadEchoHandler implements Runnable{
    private Socket socket=null;

    public ThreadEchoHandler(Socket socket) {
        this.socket=socket;
    }
    @Override
    public void run() {
        try {
            InputStream is=socket.getInputStream();
            OutputStream os=socket.getOutputStream();
            try(Scanner scanner=new Scanner(is)){
                PrintWriter pw=new PrintWriter(os,true);
                pw.println("Hello,enter bye to exit.");
                boolean done=false;
                while(!done&&scanner.hasNextLine()) {
                    String line=scanner.nextLine();
                    pw.println("Echo:"+line);
                    if(line.trim().equalsIgnoreCase("bye")) {done=true;}
                }
            }
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

URLConnection

抽象类 URLConnection 是所有类的超类,它代表应用程序和 URL 之间的通信链接。此类的实例可用于读取和写入此 URL 引用的资源。

Socket 可以默认任意类型的网络通信,URLConnection 更适合 HTTP 请求,使用 URLConnection 进行HTTP操作更方便,模拟请求报文,获取响应报文和内容。

URLConnection 常用方法

方法 说明
connect() 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)
getContentEncoding() 返回 content-encoding 头字段的值
getContentType() 返回 content-type 头字段的值
getHeaderFields() 返回头字段的不可修改的 Map
getInputStream() 返回从此打开的连接读取的输入流
setRequestProperty(String key, String value) 设置一般请求属性

获取 URLConnection 需要先创建 URL 对象:
URL url=new URL(host);

使用 URLConnection 获取网页的内容

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;

public class TestURLConnection {
    public static void main(String[] args) {
        
        try {
            //创建URL对象
            URL url=new URL("http://www.baidu.com");
            //创建 URLConnection对象
            URLConnection connection=url.openConnection();
            //设置请求属性
            //connection.setRequestProperty("", "");
            //连接
            connection.connect();
            //获取输入流
            InputStream is=connection.getInputStream();
            //通过输入流构建一个扫描器
            Scanner scanner=new Scanner(is,"utf-8");
            while(scanner.hasNextLine()) {
                String line=scanner.nextLine();
                System.out.println(line);
            }
            System.out.println("===响应头===");
            Map<String,List<String>> headers=connection.getHeaderFields();
            for (Entry<String, List<String>> entry: headers.entrySet()) {
                String key=entry.getKey();
                System.out.print(key+":");
                for (String string : entry.getValue()) {
                    System.out.print(string);
                }
                System.out.println();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
相关文章
|
1月前
|
网络协议 算法 Java
|
5天前
|
监控 Java 开发者
深入理解 Java 网络编程和 NIO
【4月更文挑战第19天】Java网络编程基于Socket,但NIO(非阻塞I/O)提升了效率和性能。NIO特点是非阻塞模式、选择器机制和缓冲区,适合高并发场景。使用NIO涉及通道、选择器和事件处理,优点是高并发、资源利用率和可扩展性,但复杂度、错误处理和性能调优是挑战。开发者应根据需求选择是否使用NIO,并深入理解其原理。
|
7天前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。
|
9天前
|
JavaScript Java 测试技术
基于Java的网络游戏交易系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络游戏交易系统的设计与实现(源码+lw+部署文档+讲解等)
23 0
|
9天前
|
SQL 安全 Java
Java安全编程:防范网络攻击与漏洞
【4月更文挑战第15天】本文强调了Java安全编程的重要性,包括提高系统安全性、降低维护成本和提升用户体验。针对网络攻击和漏洞,提出了防范措施:使用PreparedStatement防SQL注入,过滤和转义用户输入抵御XSS攻击,添加令牌对抗CSRF,限制文件上传类型和大小以防止恶意文件,避免原生序列化并确保数据完整性。及时更新和修复漏洞是关键。程序员应遵循安全编程规范,保障系统安全。
|
12天前
|
JavaScript Java 测试技术
基于Java的网络游戏交易平台信息管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络游戏交易平台信息管理系统的设计与实现(源码+lw+部署文档+讲解等)
25 1
|
14天前
|
JavaScript Java 测试技术
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
30 0
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
|
25天前
|
关系型数据库 Java 开发工具
Java入门高频考查基础知识9(15问万字参考答案)
本文探讨了Spring Cloud的工作原理,包括注册中心的心跳机制、服务发现机制,以及Eureka默认的负载均衡策略。同时,概述了Spring Boot中常用的注解及其实现方式,并深入讨论了Spring事务的注解、回滚条件、传播性和隔离级别。文章还介绍了MySQL的存储引擎及其区别,特别关注了InnoDB如何实现MySQL的事务处理。此外,本文还详细探讨了MySQL索引,包括B+树的原理和设计索引的方法。最后,比较了Git和SVN的区别,并介绍了Git命令的底层原理及流程。
32 0
Java入门高频考查基础知识9(15问万字参考答案)
|
25天前
|
存储 缓存 算法
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
最重要的是保持自信和冷静。提前准备,并对自己的知识和经验有自信,这样您就能在面试中展现出最佳的表现。祝您面试顺利!Java 是一种广泛使用的面向对象编程语言,在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性,适用于多种应用场景,包括企业应用、移动应用、嵌入式系统等。下是几个面试技巧:复习核心概念、熟悉常见问题、编码实践、项目经验准备、注意优缺点、积极参与互动、准备好问题问对方和知其所以然等,多准备最好轻松能举一反三。
49 0
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
|
25天前
|
存储 算法 JavaScript
Java入门高频考查算法逻辑基础知识3-编程篇(超详细18题1.8万字参考编程实现)
解决这类问题时,建议采取下面的步骤: 理解数学原理:确保你懂得基本的数学公式和法则,这对于制定解决方案至关重要。 优化算法:了解时间复杂度和空间复杂度,并寻找优化的机会。特别注意避免不必要的重复计算。 代码实践:多编写实践代码,并确保你的代码是高效、清晰且稳健的。 错误检查和测试:要为你的代码编写测试案例,测试标准的、边缘情况以及异常输入。 进行复杂问题简化:面对复杂的问题时,先尝试简化问题,然后逐步分析和解决。 沟通和解释:在编写代码的时候清晰地沟通你的思路,不仅要写出正确的代码,还要能向面试官解释你的
33 0