网络编程
一、网络基础:
网络通讯:我电脑输出流对你电脑输入流,你电脑输出流对我电脑输入流,说到底是IO操作
不同设备通讯都具备一套标准,我们叫OSI参考模型。
OSI参考模型 :
物理层:主要走01代码
数据链路层:主要建立逻辑上的电路,主要的协议是PPOE,拨号上网
网络层:IP寻址,主要是路由
传输层:分用和复用 端口
会话层,表示层,应用层
TCP/IP参考模型:
网络接口层
互联层
传输层
应用层
java.net.InetAddress 此类表示互联网协议 (IP) 地址。
getLocalHost();返回本地主机。
getByName(String host);在给定主机名的情况下确定主机的 IP 地址
getAllByName(String host); 在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。
getByAddress(byte[] addr);根据提供的主机名和 IP 地址创建 InetAddress。
java.net.URLDecoder和java.net.URLEncoder
package com.part01; /*URL编码,把宽字节转为单字节 http默认用的就是URL编码*/ import java.net.URLDecoder; import java.net.URLEncoder; public class Demo01 { public static void main(String[] args)throws Exception { String str="http://localhost/s?name=李四&sex=男"; String en= URLEncoder.encode(str,"utf-8"); System.out.println(en); String zh=URLDecoder.decode(en, "utf-8"); System.out.println(zh); } }
结果如下:
http%3A%2F%2Flocalhost%2Fs%3Fname%3D%E6%9D%8E%E5%9B%9B%26sex%3D%E7%94%B7 http://localhost/s?name=李四&sex=男
模拟客户端给服务器发消息:
Server类:
package com.part02; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ServerSocket;//此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果 import java.net.Socket; public class Server { public static void main(String[] args) throws Exception { //服务器端口为8080 ServerSocket server=new ServerSocket(8080); System.out.println("服务器已起动。。。。"); //accept() 侦听并接受到此套接字的连接。 Socket s=server.accept();//阻塞 等客户的到来 System.out.println("客户机连上了。。。。。"); InputStream is=s.getInputStream(); OutputStream os=s.getOutputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(is)); String str=null; while(null!=(str=br.readLine())) { System.out.println("客户机说:"+str); } System.out.println("end........"); } }
Client类:
package com.part02; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.InetAddress; import java.net.Socket;//此类实现客户端套接字,也可以就叫“套接字”,套接字是两台机器间通信的端点。 public class Client { public static void main(String[] args)throws Exception { InetAddress ip=InetAddress.getByName("192.168.197.1"); Socket s=new Socket(ip, 8080);//这一句如果能得到s 说明已经得到服务器了 PrintStream ps=new PrintStream(s.getOutputStream()); BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); String str=null; while(null!=(str=br.readLine())) { ps.println(str); } System.out.println("client end..."); } }
TCP实现客户端和服务器双向聊天:
Server类:
package com.part03; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args)throws Exception { ServerSocket server=new ServerSocket(8080); System.out.println("服务器启动..."); Socket s=server.accept(); new KeyThread(new PrintStream(s.getOutputStream())).start();//这句意思就是不断地读键盘,读到键盘以后,把数据发出去,发给它对应的输出流,给客户端了 BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));//还要不断地读客户端发来的数据 new ReadOther("Client", br).start(); } } //端口的选取范围0-65535,0-1024是系统默用端口 //服务器要不断地读客户端发来的数据,还要不断地读键盘,由键盘发出去。是用线程
KeyThread线程类
package com.part03; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; public class KeyThread extends Thread { PrintStream ps=null; public KeyThread(PrintStream ps) { this.ps=ps; } //线程代码。不断地读键盘 @Override public void run() { String str=null; BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); try { while(null!=(str=br.readLine())) { ps.println(str); } } catch (IOException e) { e.printStackTrace(); } } }
ReadOther类
package com.part03; import java.io.BufferedReader; import java.io.IOException; public class ReadOther extends Thread { BufferedReader br ; private String name; public ReadOther(String name,BufferedReader br) { this.name=name; this.br=br; } @Override public void run() { String str=null; try { while(null!=(str=br.readLine())) { System.out.println(name+":"+str); } } catch (IOException e) { e.printStackTrace(); } } }
Client类
package com.part03; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.InetAddress; import java.net.Socket; public class Client { public static void main(String[] args) throws Exception{ Socket soc=new Socket(InetAddress.getByName("192.168.197.1"),8080); PrintStream ps=new PrintStream(soc.getOutputStream()); BufferedReader br=new BufferedReader(new InputStreamReader(soc.getInputStream())); new KeyThread(ps).start(); new ReadOther("Server:", br).start(); } }
基于UDP编程,客户端发包,服务器收包:
Server类:
package com.part04; import java.net.DatagramPacket;//此类表示数据报包。可以接收也可以发送数据包 import java.net.DatagramSocket;//此类表示用来发送和接收数据报包的套接字 /*void receive(DatagramPacket p) 从此套接字接收数据报包。 void send(DatagramPacket p) 从此套接字发送数据报包*/ //用于收数据 public class Server { public static void main(String[] args)throws Exception { DatagramSocket ds=new DatagramSocket(8080); System.out.println("服务器启动........"); byte [] data=new byte[512]; //用于收数据的包 // DatagramPacket(byte[] buf, int length) 构造 DatagramPacket,用来接收长度为 length 的数据包。 DatagramPacket dp=new DatagramPacket(data, data.length); //DatagramSocket.receive(DatagramPacket p) 从此套接字接收数据报包。 ds.receive(dp);//阻塞 ,没有数据来的话,不往下执行 // String(byte[] bytes, int offset, int length) 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。 System.out.println("收到了数据---"+dp.getLength()+"---"+new String(data,0,dp.getLength())); } } //客户端给服务器发一个数据包,他不管服务器有没有收到,它的任务结束了,这是UDP(发快递) //TCP叫面向连接的协议,而UDP是不需要连接,它的性能比TCP好,不过它的丢包率比较高
Client类:
package com.part04; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class Client { public static void main(String[] args) throws Exception{ DatagramSocket ds=new DatagramSocket(); String str="大家好"; byte[]data=str.getBytes(); InetAddress ip=InetAddress.getByName("192.168.197.1"); DatagramPacket dp=new DatagramPacket(data, data.length, ip, 8080); ds.send(dp); } }
先启动Server,再启动Client类,结果如下:
服务器启动........ 收到了数据---6---大家好
用UDP来实现双向聊天的程序
Server类:
package com.part05; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress;//此类表示不带任何协议附件的 Socket Address。 import java.net.SocketException; /** * 让服务器监听8080端口,客户端是谁,他不知道,当客户端给它发一个包,它收到一个包,当他收到这个包时 他就知道这个包来自于谁,他就知道客户端的IP地址了, * 所以服务器要发包,它需要先收到一个包,所以使用UDP,第一次得发包,空包也行,目的时让服务器知道你的地址 * 双方要通讯,双方是要互发信息 * @author 0236ma * */ public class Server { int port=8080;//让服务器监听8080端口, DatagramSocket ds=null; //构建两个包,一个用来发,一用来收 DatagramPacket send=null;//发 DatagramPacket recieve=null;//收 byte [] buffer=new byte[512];//1k private BufferedReader br=null; SocketAddress sa=null;//封装了端口和IP public Server()//初始化信息 { try { ds=new DatagramSocket(port); System.out.println("start server...."); recieve=new DatagramPacket(buffer, buffer.length); //先收客户端的一个包,收这个包的目的是为了知道客户端的IP地址和端口 ds.receive(recieve);//如果这一行执行通过,说明我收到一个数据包 sa=recieve.getSocketAddress();//客户端的IP地址 System.out.println("收到客户端的一个包:"+new String(recieve.getData())+recieve.getAddress()+recieve.getPort()); //不断接受客户端发来的数据,不断地接收键盘上的数据,使用线程 //读客户端发来的数据 new Thread(new Runnable() { @Override public void run() { try { while(true) { ds.receive(recieve); System.out.println("client说:"+new String(recieve.getData())); } } catch (IOException e) { e.printStackTrace(); } } }).start(); //读键盘 String str=null; br=new BufferedReader(new InputStreamReader(System.in)); while(null!=(str=br.readLine())) { //写给客户端 byte[]tem=str.getBytes(); send=new DatagramPacket(tem, tem.length, sa); ds.send(send);//发给客户端 } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { new Server(); } }
Client类:
package com.part05; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; public class Client { int port=8080; DatagramSocket ds=null; DatagramPacket send=null;//发 DatagramPacket recieve=null;//收 byte [] buffer=new byte[512]; private BufferedReader br=null; private InetAddress ip=null; public Client() { try { ip=InetAddress.getByName("192.168.197.1"); ds=new DatagramSocket();//客戶端随机开一个端口,无需绑定port recieve=new DatagramPacket(buffer, buffer.length); byte[] hand="hi".getBytes(); send=new DatagramPacket(hand, hand.length, ip, port); ds.send(send); //读对方发来的数据 new Thread(new Runnable() { @Override public void run() { try { while(true) { ds.receive(recieve); System.out.println("Server:"+new String(recieve.getData())); } } catch (IOException e) { e.printStackTrace(); } } }).start(); //读键盘 String str=null; br=new BufferedReader(new InputStreamReader(System.in)); while(null!=(str=br.readLine())) { //写给客户端 byte[]tem=str.getBytes(); send=new DatagramPacket(tem, tem.length, ip,port); ds.send(send);//发给客户端 } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { new Client(); } }