互联网上那么多设备, 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