JavaSE| 网络编程
URL
URI(Uniform resource identifier):表示一个统一资源标识符 (URI) 引用,用来唯一的标识一个资源。
URL(Uniform Resource Locator):类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。URI不能用于定位任何资源,它的唯一作用是解析,而URL则包含一个可打开到达该资源的输入流。 URL的基本结构由5部分组成:
<传输协议>://<主机名>:<端口号>/<文件名>#片段名 <传输协议>://<主机名>:<端口号>/<文件名>?参数列表
其中#片段名:即锚点,例如看小说,直接定位到章节
例如:http://java.sun.com/index.html#chapter1
参数列表格式:参数名=参数值&参数名=参数值....
例如: http://192.168.1.100:8080/helloworld/index.jsp?username=chai&password=123
URL url = new URL("http://www.baidu.com:80/index.html?keyword=java"); System.out.println("协议:" + url.getProtocol()); System.out.println("主机名:" + url.getHost()); System.out.println("端口号:" + url.getPort()); System.out.println("文件路径:" + url.getPath()); System.out.println("文件名:" + url.getFile()); System.out.println("在文件中的相对位置(喵点):" + url.getRef());//注意如果存在锚点,那么查询名返回null,因为#后面全部当做锚点了 System.out.println("获取该url的查询名字:" + url.getQuery()); public final InputStream openStream():返回一个用于从该连接读入的 InputStream。
URL url2 = new URL("http://www.baidu.com"); InputStream input = url.openStream(); //返回一个用于从该连接读入的 InputStream byte[] data = new byte[1024]; int len; while((len = input.read(data)) != -1){ String s = new String(data, 0, len, "UTF-8"); System.out.println(s); } input.close();
URLConnection
URL的方法openStream(),能从网络上读取数据,但是无法给服务器端发送数据,若希望给服务器端发送数据,则需要URLConnection。
它代表应用程序和 URL 之间的通信链接。此类的实例可用于读取和写入此 URL 引用的资源。通常,创建一个到 URL 的连接需要几个步骤:
- 通过 URL对象调用
openConnection
方法创建URLConnection连接对象。 - 处理设置参数和一般请求属性。
- 使用
connect
方法建立到远程对象的实际连接。
远程对象变为可用。远程对象的头字段和内容变为可访问
从客户端读取发生给服务端(服务端做处理再返回给客户端)
public class TestServer { public static void main(String[] args) throws IOException { //1.开启服务,等待客户端连接 ServerSocket server = new ServerSocket(9999);//开启服务器 Socket socket = server.accept(); //接收客户的连接 System.out.println("开启服务,连接成功"); //2.接收客户端发来的消息输入: InputStream inputStream = socket.getInputStream(); //以字节流接收客户端的信息,通过socket接收 InputStreamReader isr = new InputStreamReader(inputStream); //把字节流转成字符流 BufferedReader br = new BufferedReader(isr);//提高效率加上缓冲流 //3.给客户端返回消息输出: OutputStream os = socket.getOutputStream(); //输出,通过socket输出 PrintStream ps = new PrintStream(os); //System.out.println(ps); //对接收的消息做处理 String line; while((line = br.readLine()) != null){ StringBuilder s = new StringBuilder(line); System.out.println("收到消息:" + s.toString()); s.reverse(); ps.println(s); System.out.println("已做处理:" + s); } ps.close(); os.close(); br.close(); isr.close(); inputStream.close(); socket.close(); server.close(); } }
public class Testclient {
public static void main(String[] args) throws UnknownHostException, IOException {
//1.连接服务器
Socket socket = new Socket("localhost", 9999);
//2.从键盘输入消息
Scanner input = new Scanner(System.in); //输入流inputStream
//3.输出给服务端
OutputStream outputStream = socket.getOutputStream();//以字节流通过socket输出给服务端
PrintStream ps = new PrintStream(outputStream);//按行打印
//4.接收服务端发来的消息
InputStream inputStream = socket.getInputStream(); //从网络中通过socket接收服务端发来的
InputStreamReader isr = new InputStreamReader(inputStream);//把字节流转成字符流
BufferedReader br = new BufferedReader(isr); //用缓存包装
//对键盘输入的信息做处理
while(true){
System.out.println("单词:");
String word = input.next(); //从键盘中接收消息
if("bye".equals(word)){
break;
}
System.out.println("从键盘输入:" + word);
ps.println(word); //给服务器发送单词消息; ps.print(word)用这个发送不出去!!!!
String line = br.readLine();
System.out.print("返回的单词是:" + line);
}
inputStream.close();
outputStream.close();
input.close();
socket.close();
}
}
接收多个客户端发来的消息
package com.atguigu.manytcpsendword; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class TestServer { public static void main(String[] args) throws IOException { //1. 开启服务器 ServerSocket server = new ServerSocket(8080); //2. 接收n个客户端发来的消息 while(true){ Socket socket = server.accept(); String ip = socket.getInetAddress().getHostAddress(); System.out.println(ip + "接入");//记录接入的ip地址 MyMessage m = new MyMessage(socket); //在构造器中赋值 m.start(); } } } class MyMessage extends Thread{ private Socket socket; //socket负责收发消息, public MyMessage(Socket socket) { super(); this.socket = socket; } public void run(){ InputStream is = null; InputStreamReader isr = null; BufferedReader br = null; OutputStream os = null; PrintStream ps = null; try { //1. 接收客户端发来的消息,从网络中读取-->字节流-字符流 --> is = socket.getInputStream(); isr = new InputStreamReader(is); br = new BufferedReader(isr); //2. 对接收的消息做处理然后返回给客户端 os = socket.getOutputStream(); ps = new PrintStream(os); String line; while((line = br.readLine()) != null){ //line = br.readLine(); StringBuffer s = new StringBuffer(line); s.reverse(); ps.println(s); System.out.println("已处理完毕并返回给客户端" + s); } } catch (IOException e1) { e1.printStackTrace(); } try { ps.close(); os.close(); br.close(); isr.close(); is.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } //server.close(); } }
package com.atguigu.manytcpsendword; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; public class TestClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost", 8080); Scanner input = new Scanner(System.in); //输出给服务端 OutputStream os = socket.getOutputStream(); PrintStream ps = new PrintStream(os); //接收服务端消息 InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is);//把接收的字节转成字节 BufferedReader br = new BufferedReader(isr); //把字节包装下提高效率 while(true){ System.out.println("留言:"); String str = input.next(); if("bye".equalsIgnoreCase(str)){ break; } //给服务端发 消息 ps.println(str); //接收服务端发来的消息 String line = br.readLine(); System.out.println("接收到服务端发来的消息:" + line); } br.close(); isr.close(); is.close(); ps.close(); os.close(); input.close(); socket.close(); } }
传输文件
public class Server {
public static void main(String[] args) throws IOException {
//1.创建服务器
ServerSocket server = new ServerSocket(9999);
Socket socket = server.accept();
String ip = socket.getInetAddress().getHostAddress();
System.out.println(ip + "已接入");
//2.从客户端读取数据
DataInputStream dis = new DataInputStream(socket.getInputStream());
String fileName = dis.readUTF();
//先确定输出文件的路径,然后再写入数据
FileOutputStream fos = new FileOutputStream("upload/" + fileName);
//读取内容
byte[] data = new byte[1024];
int len;
while((len = dis.read(data)) != -1){
fos.write(data, 0, len);
}
//3.写完之后给客户端回个信号
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("接收完毕,请客户端查阅");
ps.close();
fos.close();
dis.close();
socket.close();
server.close();
}
}
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
//1.连接服务器
Socket socket = new Socket("localhost", 9999);
//2.给服务器上传文件
//一.先输入地址
Scanner input = new Scanner(System.in);
System.out.println("文件地址:");
String filePath = input.next();
File file = new File(filePath); //因为它是一个file字符串路径对象,所以要用DataIn。。
String pathName = file.getName();
//二.把文件路径和文件名对象化传给服务端
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(pathName); //对象化文件名后,读取时还要同样的readUTF( )
//三.按照字节读取文件内容
FileInputStream fis = new FileInputStream(file);
byte[] data = new byte[1024];
int len;
while((len = fis.read(data)) != -1){ //读取文件内容并写入
dos.write(data, 0, len);
}
socket.shutdownOutput(); //要先关闭输出流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //接收服务端返回的字符串
String line = br.readLine();
System.out.println("接收服务端返回的结果:" + line);
br.close();
fis.close();
dos.close();
input.close();
socket.close();
}
}
可接收多个客户端发来的文件
package com.atguigu.fileputmany; import java.io.DataInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { //1.创建服务器 ServerSocket server = new ServerSocket(9999); while(true){ Socket socket = server.accept(); String ip = socket.getInetAddress().getHostAddress(); System.out.println(ip + "已接入"); MyFile m = new MyFile(socket); m.start(); } } } class MyFile extends Thread{ private Socket socket; public MyFile(Socket socket) { super(); this.socket = socket; } public void run(){ //2.从客户端读取数据 DataInputStream dis = null; FileOutputStream fos = null; PrintStream ps = null; try { dis = new DataInputStream(socket.getInputStream()); String fileName = dis.readUTF(); //先确定输出文件的路径,然后再写入数据 fos = new FileOutputStream("upload/" + fileName); //读取内容 byte[] data = new byte[1024]; int len; while((len = dis.read(data)) != -1){ fos.write(data, 0, len); } //3.写完之后给客户端回个信号 ps = new PrintStream(socket.getOutputStream()); ps.println("接收完毕,请客户端查阅"); } catch (IOException e1) { e1.printStackTrace(); } try { ps.close(); fos.close(); dis.close(); socket.close(); //server.close(); } catch (IOException e) { e.printStackTrace(); } } }
package com.atguigu.fileputmany; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; public class Client { public static void main(String[] args) throws UnknownHostException, IOException { //1.连接服务器 Socket socket = new Socket("localhost", 9999); //2.给服务器上传文件 //一.先输入地址 Scanner input = new Scanner(System.in); System.out.println("文件地址:"); String filePath = input.next(); File file = new File(filePath); //因为它是一个file字符串路径对象,所以要用DataIn。。 String pathName = file.getName(); //二.把文件路径和文件名对象化传给服务端 DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); dos.writeUTF(pathName); //对象化文件名后,读取时还要同样的readUTF( ) //三.按照字节读取文件内容 FileInputStream fis = new FileInputStream(file); byte[] data = new byte[1024]; int len; while((len = fis.read(data)) != -1){ //读取文件内容并写入 dos.write(data, 0, len); } socket.shutdownOutput(); //要先关闭输出流,不然接收不到服务端返回的消息 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //接收服务端返回的字符串 String line = br.readLine(); System.out.println("接收服务端返回的结果:" + line); br.close(); fis.close(); dos.close(); input.close(); socket.close(); } }
用TCP实现多人聊天
package com.atguigu.chat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; public class TestServer { public static void main(String[] args) throws IOException { //1.启动服务器 ServerSocket server = new ServerSocket(9999); ArrayList<Socket> onLine = new ArrayList<Socket>(); //创建集合装开启的线程; while(true){ Socket socket = server.accept(); System.out.println(socket.getInetAddress().getHostAddress() + "连接成功"); //每连接一个,往里边放一个 onLine.add(socket); Message m = new Message(socket, onLine); m.start(); } } } class Message extends Thread{ private Socket socket; private ArrayList<Socket> onLine; private String ip; public Message(Socket socket, ArrayList<Socket> onLine) { super(); this.socket = socket; this.onLine = onLine; } public void run(){ ip = socket.getInetAddress().getHostAddress(); sendToOther(ip + "上线了"); //小功能,xx上线了,在receive公共聊天室; BufferedReader br = null; try { //接收客户端的消息; 把字节变成字符流并提高效率 br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line; while((line = br.readLine()) != null){ //把消息转发给其他的客户端receive公共聊天室;这里写一个方法 sendToOther(line); } } catch (IOException e) { e.printStackTrace(); }finally { try { br.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } onLine.remove(socket); sendToOther(ip + "下线了"); } } public void sendToOther(String str){ ArrayList<Socket> offline = new ArrayList<Socket>(); for (Socket socket :onLine) { //遍历的是onLine!!!! if(!(socket.equals(this.socket))){ //如果不是自己就转发 try{ PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println(str); }catch(IOException e){ e.printStackTrace(); offline.add(socket); } } } for (Socket off : offline) { offline.remove(off); } } }
package com.atguigu.chat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; public class TestClient { public static void main(String[] args) throws UnknownHostException, IOException { //1.连接服务器 Socket socket = new Socket("localhost",9999); //创建两个线程,一个用来发send消息; 一个用来接收receive消息(作为公共的聊天场所) Send send = new Send(socket); Receive receive = new Receive(socket); send.start(); receive.start(); try { send.join(); receive.setExited(true); receive.join(); } catch (InterruptedException e) { e.printStackTrace(); } socket.close(); } } class Send extends Thread{ private Socket socket; public Send(Socket socket) { super(); this.socket = socket; } public void run(){ Scanner input = new Scanner(System.in); //从键盘输入消息 PrintStream ps = null; try { ps = new PrintStream(socket.getOutputStream());//将键盘输入的消息发出 while(true){ System.out.println("畅聊:"); String message = input.nextLine(); if("bye".equalsIgnoreCase(message)){ break; } ps.println(message); //发送出去; } } catch (IOException e) { e.printStackTrace(); } finally{ input.close(); } } } class Receive extends Thread{ private Socket socket; private boolean exited; public Receive(Socket socket) { super(); this.socket = socket; } public void setExited(boolean exited) { this.exited = exited; } public void run(){ BufferedReader br = null; try { //字节输入流 -->字符 --> 包装下提高效率 br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line; while((line = br.readLine()) != null && !exited){ System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
基于UDP多人聊天(使用MulticastSocket实现多点广播)
package com.atguigu.udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.util.Scanner; public class TestMulticastSocket { static Scanner input = new Scanner(System.in); static String username; public static void main(String[] args) throws IOException { //1. 创建Socket MulticastSocket ms = new MulticastSocket(9999); InetAddress ip = InetAddress.getByName("230.0.0.1"); ms.joinGroup(ip); //把这个ms添加到广播组中 ms.setLoopbackMode(false); //如果为true是禁止回传; System.out.println("用户名:"); username = input.nextLine(); Send send = new Send(ms, ip); Receive receive = new Receive(ms); send.start(); receive.start(); try { send.join(); receive.setExited(true); receive.join(); } catch (InterruptedException e) { e.printStackTrace(); } ms.close(); } static class Send extends Thread{ //静态内部类 private MulticastSocket socket; //类 private InetAddress ip; //类 public Send(MulticastSocket socket, InetAddress ip) { super(); this.socket = socket; this.ip = ip; } public void run(){ while(true){ System.out.println("输入消息:"); String message = input.nextLine(); if("bye".equalsIgnoreCase(message)){ break; } //1.创建数据报DatagramPacket byte[] data = (username + "说:" + message).getBytes(); //把键盘输入的转成字节数组 DatagramPacket dp = new DatagramPacket(data, data.length, ip, 9999); try { //2.调用调用MulticastSocket类socket 的send方法将数据报发送出去; socket.send(dp); } catch (IOException e) { e.printStackTrace(); } } } } static class Receive extends Thread{ private MulticastSocket socket; private boolean exited; public Receive(MulticastSocket socket) { super(); this.socket = socket; } public void setExited(boolean exited) { this.exited = exited; } public void run(){ while(!exited){ //1.建立数据报DatagramPacket byte[] data = new byte[1024]; DatagramPacket dp = new DatagramPacket(data, data.length); try { //2.调用MulticastSocket socket的seceive方法发送数据报; socket.receive(dp); //3.拆解数据报 int len = dp.getLength(); System.out.println("本次收到的消息:" + new String(data, 0, len)); } catch (IOException e) { e.printStackTrace(); } } } } }
基于UDP协议的网络编程
TCP:(Transmission Control Protocol,传输控制协议),面向连接的,可靠的,基于字节流的传输层的网络协议。
服务器端:ServerSocket和Socket,客户端:Socket
getInputStream()和getOutputStream()
UDP:(User Datagram Protocol,用户数据报协议),非面向连接的(无连接的),面向事务的基于数据报的不可靠的传输层的网络协议。
UDP:快,适用于(是否接收到消息要求不高,但是对速度要求高,必须小的),大小限制在64K
通信的两端也有Socket:DatagramSocket
DatagramPacket数据报
1、“发送端”
步骤流程:
1、建立发送端的DatagramSocket,需要指定本端的端口号
2、建立数据包DatagramPacket
数据
接收端的IP地址
接收端的端口号
3、调用DatagramSocket的发送方法
4、关闭DatagramSocket
2、“接收端”
步骤流程:
1、建立接收端的DatagramSocket,需要指定本端的IP地址和端口号
2、建立数据包DatagramPacket
需要指定装数据的数组
3、调用Socket的接收方法
4、拆封数据
5、关闭Socket