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();
        }
    }
}

转载于:https://www.cnblogs.com/AIThink/p/9911798.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值