当前位置: 代码迷 >> 综合 >> JavaSE——网络编程
  详细解决方案

JavaSE——网络编程

热度:115   发布时间:2023-11-01 16:57:12.0

网络编程

什么是服务器?

? 服务器就是一台电脑,就是一台计算机,只不过配置非常高。

以前的代码:

? 都是在自己的电脑上运行的。一些结果也是打印在控制台或者是保存到文件中的。没有一个交互性的效果。

现在学习了网络编程,可以实现计算机跟计算机之间可以传输数据(交互)。

简单理解:你可以给你的同桌发消息了。你的同桌也可以接收到你的消息了。

什么是网络编程?

? 计算机跟计算机之间通过网络进行数据传输。

常见的互联网架构?

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,再按照下面的图解进行设置即可。
同时运行多个main方法

代码示例:

客户端(发送端)

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里面}}
}