最近在作一个项目的时候,由于项目要求跨域链接。因此,使用了Okhttp框架。其内部原理是基于 socket 网络编程的。由于本身在这方面比较薄弱,因此写这一篇文章进行相关的总结。html
一、TCP/IP 参考模型
这位大佬写的很详细---点击即看java
二、socket 套接字
每一个套接字都是链接的一个端点,有相应的套接字地址。由一个IP地址与16位的整数端口组成.一个链接由两端的套接字地址惟一肯定。叫套接字对。
如:(cliaddr:cliport, servaddr:servport)
端口号分为:
标准既定的端口号: 0~49151. 其中知名端口号由 0~1023 ** 组成。FTP 通常使用 21号端口号,HTTP 通讯通常使用 80 号端口号。
动态分配的端口号: 49152~65535. 操做系统为之分配不一样的端口号。而后应用程序使用时,由操做系统将链接创建。linux
三、java 中的网络编程类android
InetAddress:用于标识网络上的硬件资源,主要是IP地址 URL:统一资源定位符,经过URL能够直接读取或写入网络上的数据 Sockets:使用TCP协议实现的网络通讯Socket相关的类 Datagram:使用UDP协议,将数据保存在用户数据报中,经过网络进行通讯。UDP协议中,使用 数据报 为传输单位。
InetAddress类用于标识网络上的硬件资源,标识互联网协议(IP)地址。程序员
//获取本机的InetAddress实例 InetAddress address =InetAddress.getLocalHost(); //获取计算机名 address.getHostName(); //获取IP地址 address.getHostAddress(); //获取字节数组形式的IP地址,以点分隔的四部分 byte[] bytes = address.getAddress(); //获取其余主机的InetAddress实例 InetAddress address2 =InetAddress.getByName("其余主机名"); InetAddress address3 =InetAddress.getByName("IP地址");
URL(Uniform Resource Locator)统一资源定位符,表示Internet上某一资源的地址,协议名:资源名称编程
//建立一个URL的实例 URL myBlog =new URL("https://3dot141.cn"); URL url =new URL(myBlog,"/blogs/33521.html?username=3dot141#test");//?表示参数,#表示锚点 url.getProtocol();//获取协议 url.getHost();//获取主机 url.getPort();//若是没有指定端口号,根据协议不一样使用默认端口。此时getPort()方法的返回值为 -1 url.getPath();//获取文件路径 url.getFile();//文件名,包括文件路径+参数 url.getRef();//相对路径,就是锚点,即#号后面的内容 url.getQuery();//查询字符串,即参数
//使用URL读取网页内容 //建立一个URL实例 URL url =new URL("http://www.baidu.com"); InputStream is = url.openStream();//经过openStream方法获取资源的字节输入流 InputStreamReader isr =newInputStreamReader(is,"UTF-8");//将字节输入流转换为字符输入流,若是不指定编码,中文可能会出现乱码 BufferedReader br =newBufferedReader(isr);//为字符输入流添加缓冲,提升读取效率 String data = br.readLine();//读取数据 while(data!=null){ System.out.println(data);//输出数据 data = br.readerLine(); } br.close(); isr.colose(); is.close();
首先介绍下关于 linux 下的套接字链接原理,帮助理解json
下面介绍java 下 Socket的使用跨域
(1)Socket() (2)Socket(InetAddress address, int port)throws UnknownHostException,IOException // 设定远程服务器地址与客户端地址 (3)Socket(InetAddress address, int port, InetAddress localAddr, int localPort)throws IOException (4)Socket(String host, int port) throws UnknownHostException,IOException // 设定远程服务器地址与客户端地址 (5)Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException
1. getInetAddress():得到远程服务器的IP地址。 2. getPort():得到远程服务器的端口。 3. getLocalAddress():得到客户本地的IP地址。 4. getLocalPort():得到客户本地的端口。 5. getInputStream():得到输入流。若是Socket尚未链接,或者已经关闭,或者已经经过shutdownInput()方法关闭输入流,那么此方法会抛出IOException。 6. getOutputStream():得到输出流。若是Socket尚未链接,或者已经关闭,或者已经经过shutdownOutput()方法关闭输出流,那么此方法会抛出IOException。
1. close() // 状态测试方法 1. isClosed() 2. IsConnected() 3. isBound()
1. shutdownInput() 2. shutdownOutput() // 状态测试方法 1. isInputShutDown() 2. isOutputShutdown()
以上就是 Socket 类的基本方法。 下面让咱们进入实战,来看一下,Socket 类如何使用数组
/** * 基于TCP协议的Socket通讯,实现用户登陆,服务端 */ //一、建立一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 ServerSocket serverSocket =newServerSocket(33521);//1024-65535的某个端口 //二、调用accept()方法开始监听,等待客户端的链接 Socket socket = serverSocket.accept(); //三、获取输入流,并读取客户端信息 InputStream is = socket.getInputStream(); InputStreamReader isr =newInputStreamReader(is); BufferedReader br =newBufferedReader(isr); String info =null; while((info=br.readLine())!=null){ System.out.println("我是服务器,客户端说:"+info); } socket.shutdownInput();//关闭输入流 //四、获取输出流,响应客户端的请求 OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.write("欢迎您!"); pw.flush(); //五、关闭资源 pw.close(); os.close(); br.close(); isr.close(); is.close(); socket.close(); serverSocket.close();
//客户端 //一、建立客户端Socket,指定服务器地址和端口 Socket socket =newSocket("localhost",33521); //二、获取输出流,向服务器端发送信息 OutputStream os = socket.getOutputStream();//字节输出流 PrintWriter pw =newPrintWriter(os);//将输出流包装成打印流 pw.write("用户名:3dot141;密码:hahah"); pw.flush(); socket.shutdownOutput(); //三、获取输入流,并读取服务器端的响应信息 InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String info = null; while((info=br.readLine())!null){ System.out.println("我是客户端,服务器说:"+info); } //四、关闭资源 br.close(); is.close(); pw.close(); os.close(); socket.close();
我是服务器,客户端说:用户名:3dot141;密码:hahah 我是客户端,服务器说:欢迎您!
多线程中的运用服务器
public class ServerThread implements runnable{ //服务器线程处理 //和本线程相关的socket Socket socket =null; // public ServerThread(Socket socket){ this.socket = socket; } publicvoid run(){ //服务器处理代码 } } //服务器代码 ServerSocket serverSocket =newServerSocket(33521); Socket socket =null; int count =0;//记录客户端的数量 while(true){ socket = serverScoket.accept(); ServerThread serverThread =new ServerThread(socket); serverThread.start(); count++; System.out.println("客户端链接的数量:"+count); }
UDP 是面向无链接的协议,反应迅速,适用于适时场景,可是丢包后不能发现。
用于 直播等网速要求较高的应用
DatagramSocket
端到端的通讯类.
//本机地址 // 随机 DatagramSocket() // 指定 DatagramSocket(int port, InetAddress) // 发送与接收 send(DatagramPacket) receive(DatagramPacket)
DatagramPacket
数据报, 为 IP 和 UDP 等网络层以上的包的单位 。虽然这些都是包,但不一样的层拥有不一样的称呼。数据链路层中 叫 帧 , TCP 则表示 为 段 .
方法 :
// 构造方法 // 接收时 DatagramPacket(byte[] buf, int length); // 发送时 DatagramPacket(byte[] buf, int length, InetAddress iAdrr, int Port); // 使用方法 // 用于服务器得到 客户端地址 getAddress() // 用于服务器得到 客户端接口 getPort()
//服务器端,实现基于UDP的用户登陆 //一、建立服务器端DatagramSocket,指定端口 DatagramSocket socket =new datagramSocket(33521); //二、建立数据报,用于接受客户端发送的数据 byte[] data =newbyte[1024];// DatagramPacket packet =newDatagramPacket(data,data.length); //三、接受客户端发送的数据 socket.receive(packet);//此方法在接受数据报以前会一致阻塞 //四、读取数据 String info =newString(data,o,data.length); System.out.println("我是服务器,客户端告诉我"+info); //========================================================= //向客户端响应数据 //一、定义客户端的地址、端口号、数据 // 这里也能够本身设置 InetAddress address = packet.getAddress(); int port = packet.getPort(); byte[] data2 = "欢迎您!".geyBytes(); //二、建立数据报,包含响应的数据信息 DatagramPacket packet2 = new DatagramPacket(data2,data2.length,address,port); //三、响应客户端 socket.send(packet2); //四、关闭资源 socket.close();
//客户端 //一、定义服务器的地址、端口号、数据 InetAddress address =InetAddress.getByName("localhost"); int port =33521; byte[] data ="用户名:3dot141;密码:hahah".getBytes(); //二、建立数据报,包含发送的数据信息 DatagramPacket packet = newDatagramPacket(data,data,length,address,port); //三、建立DatagramSocket对象 DatagramSocket socket =newDatagramSocket(); //四、向服务器发送数据 socket.send(packet); //接受服务器端响应数据 //====================================== //一、建立数据报,用于接受服务器端响应数据 byte[] data2 = new byte[1024]; DatagramPacket packet2 = new DatagramPacket(data2,data2.length); //二、接受服务器响应的数据 socket.receive(packet2); String raply = new String(data2,0,packet2.getLenth()); System.out.println("我是客户端,服务器说:"+reply); //四、关闭资源 socket.close();
在项目中,我对 OkHttp 进行了简单的封装,基本知足我在项目中的须要。
下面贴上个人 工具类
public class OkhttpUtil { public static final MediaType JSON = MediaType.parse("application/json;charset=UTF-8"); public static String doGet(String url) throws IOException { OkHttpClient client = new OkHttpClient(); Request get = new Request.Builder().url(url).build(); Response response = client.newCall(get).execute(); return response.body().string(); } public static String doGet(String url, Map<String, String> map) throws IOException { OkHttpClient client = new OkHttpClient(); String newUrl = url; if (map != null) { int loop = 0; for (String key : map.keySet()) { if (loop == 0) { newUrl = newUrl + "?" + key + "=" + map.get(key); } else { newUrl = newUrl + "&" + key + "=" + map.get(key); } loop = 1; } } Request get = new Request.Builder().url(newUrl).build(); Response response = client.newCall(get).execute(); return response.body().string(); } public static String doPost(String url, String requestBody) throws IOException { OkHttpClient client = new OkHttpClient(); Request post = new Request.Builder().url(url).post(RequestBody.create(JSON, requestBody)).build(); Response response = client.newCall(post).execute(); if (!response.isSuccessful()) { throw new IOException("没能获得数据" + response); } return response.body().string(); } }
若是有对 okhttp 框架感兴趣的,能够参阅下面的网址。我就不献丑了。
okhttp 源码解析
okhttp 使用教程
路漫漫其修远兮,吾将上下而求索。
在程序员的道路上,我还只是一个刚上路的小学生,怀着对代码世界的向往,砥砺前行。
stay hungry, stay foolish
与诸君共勉。
您的每一次点赞,关注都是对个人一种激励。
个人我的博客 -- killCode谢谢。