网络编程
什么是服务器?
? 服务器就是一台电脑,就是一台计算机,只不过配置非常高。
以前的代码:
? 都是在自己的电脑上运行的。一些结果也是打印在控制台或者是保存到文件中的。没有一个交互性的效果。
现在学习了网络编程,可以实现计算机跟计算机之间可以传输数据(交互)。
简单理解:你可以给你的同桌发消息了。你的同桌也可以接收到你的消息了。
什么是网络编程?
? 计算机跟计算机之间通过网络进行数据传输。
常见的互联网架构?
BS、CS
BS和CS的优缺点
BS:
- ? 优点:不需要下载客户端,使用起来非常方便。
- ? 缺点:用户体验比较差,画面不够精美。
CS:
- ? 缺点:需要下载客户端,而且每一次要更新内容的时候,都要更新客户端,甚至要重新下载,非常麻烦。
- ? 优点:画面非常精美,用户体验比较好。
在以后实际开发中,根据企业的项目需求来,如果是一些电商,新闻的项目对页面要求不高,可以用BS。
这也是为什么,在电脑上,京东,淘宝,新浪新闻都是BS的原因。
在以后实际开发中,如果对画面有强大的要求,一定是用CS,比如游戏。
网络编程三要素
IP、端口、协议
IP:
- 设备在互联网中的地址,唯一的标识。
IP分类:
? 公网IP,局域网IP
? 公网IP:对外,在上外网的时候需要使用的。
? 局域网IP:192.168开头都是局域网地址。作用:节约IP的使用。
常用命令
? ipconfig:查看本机IP地址
? ping + IP:检查你的电脑跟指定IP的电脑之间网络是否畅通
####扩展:
? ping + 域名 — ping www.baidu.com
####特殊IP:
? 127.0.0.1,也可以是localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。
####问题:(了解扩展)
? 假设,我的点IP是192.168.1.255,那么这个IP跟127.0.0.1有什么区别?
共同点:都是表示自己的电脑
区别:192.168.1.255是路由器给你分配的。127.0.0.1(localhost)就表示本机不是路由器分配的。
IP的两种表示形式
IPV4、IPV6
IPV4:32bit位,全球最多只能有42亿多,不够了。渐渐会被IPV6替代。
IPV6:128bit位,足够使用。
InetAddress类
常用方法:
getByName :确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
getHostName:获取主机名
getHostAddress :获取IP
代码示例:
//1.获取一个IP地址(在网络中计算机的对象)
InetAddress address = InetAddress.getByName("192.168.89.92");//2.获取主机名获取ip地址
//细节:如果能获取到主机名返回的就是主机名
//但是如果有的情况下,获取不到,返回的就是ip地址
String hostName = address.getHostName();
System.out.println(hostName);//3.获取IP
String ip = address.getHostAddress();
System.out.println(ip);
端口:
一般也会成为端口号。是应用程序在设备中唯一的标识。
一个端口只能被一个应用程序绑定。
一个应用程序可以绑定多个端口。
举例:
10000端口,如果被QQ绑定了,那么10000这个端口就不能再被其他软件绑定了。
但是QQ可以绑定10000,还可以绑定其他端口。
端口号的注意点:
端口号的范围:0~65535
0~1023之间的端口号已经被系统或者一些知名的网络应用给占用了。
? 比如浏览器80端口 tomcat:8080,Mysql:3306
我们自己在使用的时候,需要用1024以上的端口。
扩展(了解)
我怎么知道系统当中有哪些端口被被人占用了呢?
1,我们下午会写代码去绑定端口,你可以随便绑定一个,如果该端口被占用,那么代码就会报错。
? 如果该端口没有被占用,那么就不会报错。
2,我们可以使用一些第三方软件进行查询。(鲁大师,360,等一下杀毒软件)
以360为例:点功能大全 —> 流量防火墙 —>网络连接可以看到
协议:
数据在网络中传输的规则。常见:UDP,TCP。
UDP:
? 面向无连接的协议。(发送数据的时候不保证连接已经建立)
? 速度快,大小限制最多64K,数据不安全,数据容易丢失。
TCP:
? 面向连接的协议。(发送数据的时候需要保证连接已经建立)
? 速度慢,没有大小限制,数据安全。
应用场景(了解,扩展)
UDP:一般来讲对速度比较有要求,但是数据丢失一点没有什么太大的关系。
? 看电影、视频网络会议。
TCP:一般是对数据安全有要求的情况下。
? 下载安装包,聊天。
UDP协议发送和接收数据
发送端:
public class Client {
public static void main(String[] args) throws IOException {
//1.创建码头//如果没有绑定端口,那么系统会让程序绑定一个随机的可用端口DatagramSocket ds = new DatagramSocket();//2.确定要发送的数据String s = "吃俺老孙一棒棒";byte[] bytes = s.getBytes();//3.确定要发送的计算机InetAddress address = InetAddress.getByName("127.0.0.1");//4.确定要发送的端口int port = 10000;//5.把上面的数据,计算机,端口打包在一起DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);//6.发送数据ds.send(dp);//7.释放资源ds.close();}
}
接收端:
public class Server {
public static void main(String[] args) throws IOException {
//1.创建码头的对象//接收端,在创建对象的时候需要绑定端口//表示哥们要从10000端口接收数据DatagramSocket ds = new DatagramSocket(10000);//因为我们只要接收即可//所以,在箱子中,只要准备装数据的数组即可//IP和端口号,在发送数据的时候才需要。//2.创建一个新的包裹,用于接收数据DatagramPacket dp = new DatagramPacket(new byte[1024],1024);//3.接收数据ds.receive(dp);//4.从包裹中获取数据byte[] bytes = dp.getData();int len = dp.getLength();String ip = dp.getAddress().getHostAddress();System.out.println(ip + "发送过来了:" + new String(bytes,0,len));//5.释放资源ds.close();}
}
练习:UDP的聊天室
需求:
? 按照下面的要求实现程序
UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束
UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收
操作细节:
? 需要把发送端运行多次。
? idea默认只能运行一次,所以需要进行配置。
? 需要保证第一个红色箭头是当前要运行多次的类,再点击下面的Edit Configurations,再按照下面的图解进行设置即可。
代码示例:
客户端(发送端)
public class Client {
public static void main(String[] args) throws IOException {
//UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束//1. 创建码头对象DatagramSocket ds = new DatagramSocket();Scanner sc = new Scanner(System.in);while (true) {
//2.数据是键盘录入System.out.println("请输出要聊天的内容");String line = sc.nextLine();if("886".equals(line)){
break;}byte[] bytes = line.getBytes();//3.确定接收端InetAddress address = InetAddress.getByName("127.0.0.1");//4.确定端口int port = 10000;DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);//5.发送数据ds.send(dp);}//6.释放资源ds.close();}
}
服务端(接收端):
public class Server {
//服务器public static void main(String[] args) throws IOException {
//1.创建码头对象//需要绑定端口,表示在绑定的端口上接收数据//要跟发送端发送的端口保持一致DatagramSocket ds = new DatagramSocket(10000);//2.创建数据包DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);//3.循环接收数据while (true) {
ds.receive(dp);//4.获取数据并打印byte[] bytes = dp.getData();int len = dp.getLength();String ip = dp.getAddress().getHostAddress();System.out.println(ip + "发送过来了:" + new String(bytes, 0, len));}//在公司一般来讲,服务器不关机//所以服务器不需要释放资源}
}
TCP协议发送和接收数据
客户端:
public class Client {
public static void main(String[] args) throws IOException {
//1,创建客户端Socket对象//去跟127.0.0.1的10000端口进行连接,如果连接不上,直接报错Socket socket = new Socket("127.0.0.1",10000);//2.从连接中,获取输出流,往服务器写数据OutputStream os = socket.getOutputStream();//3.写出数据String s = "abc";os.write(s.getBytes());//4.释放资源socket.close();}
}
服务端:
public class Server {
public static void main(String[] args) throws IOException {
//1.创建服务端对象,并绑定10000端口ServerSocket ss = new ServerSocket(10000);//2.等待客户端链接//此时服务端在accept方法这里,死等客户端来链接//如果有客户端来链接,会返回客户端的连接对象Socket socket = ss.accept();//3.从连接通道中获取流读数据InputStream is = socket.getInputStream();//4.因为不知道发了多少数据,所以循环读取int b;while ((b = is.read()) != -1){
System.out.println((char)b);}//5.释放资源//断开和客户端之间的连接socket.close();//关闭服务器ss.close();}
}
3.7 文件上传
import java.io.*;
import java.net.Socket;//给服务端上传文件
public class Client {
public static void main(String[] args) throws IOException {
//1.创建对象并连接服务器Socket socket = new Socket("127.0.0.1",10000);//2.读取本地文件并写到服务器//2.1创建本地的字节输入流对象,准备读取本地文件FileInputStream fis = new FileInputStream("meinv.jpg");//2.2获取客户端的输出流,准备往服务器写出数据OutputStream os = socket.getOutputStream();//2.3循环读取数据并写到服务器int b;//表示当前从文件中读取到的数据while((b = fis.read()) != -1){
System.out.println(1);os.write(b);//把这个数据写到服务器}//给服务端一个结束标记socket.shutdownOutput();System.out.println("客户端上传文件完毕");//接收服务端返回的数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String serverMessage = br.readLine();System.out.println(serverMessage);//3.释放资源socket.close();}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;public class Server {
public static void main(String[] args) throws IOException {
//1.开启服务ServerSocket ss = new ServerSocket(10000);//2.等待客户端链接Socket socket = ss.accept();//3.获取输入流,准备接收客户端发送过来的数据InputStream is = socket.getInputStream();//生成一个随机的文件名String fileName = UUID.randomUUID().toString().replace("-", "");//创建本地的字节输出流对象,准备把读取到的数据保存到本地FileOutputStream fos = new FileOutputStream("day12-code\\serverfile\\" + fileName + ".jpg");//循环读取数据,并写到本地int b;//此时读到了shutdownOutput的结束标记while ((b = is.read()) != -1) {
fos.write(b);}System.out.println("看看我执行了吗?");//给客户端返回上传成功的信息PrintStream ps = new PrintStream(socket.getOutputStream());ps.println("上传成功");//释放资源socket.close();ss.close();}
}
文件上传多线程版
客户端
//给服务端上传文件
public class Client {
public static void main(String[] args) throws IOException {
//1.创建对象并连接服务器Socket socket = new Socket("127.0.0.1",10000);//2.读取本地文件并写到服务器//2.1创建本地的字节输入流对象,准备读取本地文件FileInputStream fis = new FileInputStream("meinv.jpg");//2.2获取客户端的输出流,准备往服务器写出数据OutputStream os = socket.getOutputStream();//2.3循环读取数据并写到服务器int b;//表示当前从文件中读取到的数据while((b = fis.read()) != -1){
System.out.println(1);os.write(b);//把这个数据写到服务器}//给服务端一个结束标记socket.shutdownOutput();System.out.println("客户端上传文件完毕");//接收服务端返回的数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String serverMessage = br.readLine();System.out.println(serverMessage);//3.释放资源socket.close();}
}
服务端:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;public class Server {
public static void main(String[] args) throws IOException {
//1.开启服务ServerSocket ss = new ServerSocket(10000);while(true){
//2.等待客户端链接Socket socket = ss.accept();//一旦有客户端来链接。就开启线程去进行处理new Thread(//线程要处理的任务()->{
try {
//3.获取输入流,准备接收客户端发送过来的数据InputStream is = socket.getInputStream();//生成一个随机的文件名String fileName = UUID.randomUUID().toString().replace("-", "");//创建本地的字节输出流对象,准备把读取到的数据保存到本地FileOutputStream fos = new FileOutputStream("day12-code\\serverfile\\" + fileName + ".jpg");//循环读取数据,并写到本地int b;//此时读到了shutdownOutput的结束标记while ((b = is.read()) != -1) {
fos.write(b);}System.out.println("看看我执行了吗?");//给客户端返回上传成功的信息PrintStream ps = new PrintStream(socket.getOutputStream());ps.println("上传成功");//断开客户端的连接socket.close();} catch (IOException e) {
e.printStackTrace();} finally {
//释放资源的代码一般都是写在finally里面}}).start();}//服务器不关机//ss.close();}
}
3.9 文件上传线程池版
客户端:
import java.io.*;
import java.net.Socket;//给服务端上传文件
public class Client {
public static void main(String[] args) throws IOException {
//1.创建对象并连接服务器Socket socket = new Socket("127.0.0.1",10000);//2.读取本地文件并写到服务器//2.1创建本地的字节输入流对象,准备读取本地文件FileInputStream fis = new FileInputStream("meinv.jpg");//2.2获取客户端的输出流,准备往服务器写出数据OutputStream os = socket.getOutputStream();//2.3循环读取数据并写到服务器int b;//表示当前从文件中读取到的数据while((b = fis.read()) != -1){
System.out.println(1);os.write(b);//把这个数据写到服务器}//给服务端一个结束标记socket.shutdownOutput();System.out.println("客户端上传文件完毕");//接收服务端返回的数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String serverMessage = br.readLine();System.out.println(serverMessage);//3.释放资源socket.close();}
}
服务端:
public class Server {
public static void main(String[] args) throws IOException {
//创建线程池ExecutorService pool = Executors.newFixedThreadPool(10);//1.开启服务ServerSocket ss = new ServerSocket(10000);while(true){
//2.等待客户端链接Socket socket = ss.accept();//一旦有客户端来链接。就提交给线程池pool.submit(new ServerThread(socket));}//服务器不关机//ss.close();}
}
服务端线程类:
public class ServerThread implements Runnable {
Socket socket;public ServerThread(Socket socket){
this.socket = socket;}@Overridepublic void run() {
try {
//3.获取输入流,准备接收客户端发送过来的数据InputStream is = socket.getInputStream();//生成一个随机的文件名String fileName = UUID.randomUUID().toString().replace("-", "");//创建本地的字节输出流对象,准备把读取到的数据保存到本地FileOutputStream fos = new FileOutputStream("day12-code\\serverfile\\" + fileName + ".jpg");//循环读取数据,并写到本地int b;//此时读到了shutdownOutput的结束标记while ((b = is.read()) != -1) {
fos.write(b);}System.out.println("看看我执行了吗?");//给客户端返回上传成功的信息PrintStream ps = new PrintStream(socket.getOutputStream());ps.println("上传成功");//断开客户端的连接socket.close();} catch (IOException e) {
e.printStackTrace();} finally {
//释放资源的代码一般都是写在finally里面}}
}