一 灵感:
在2022年的暑假,也就是我即将迈进高三的那个暑假,我并没有察觉自己应该要学习了,还是和过往的暑假一样玩着王者荣耀,凌晨2点睡觉,中午12点起床。我依稀记得这种状态一直持续到8月19。然而离开学还有6天时。我肚子开始剧烈的疼痛。想了一切可以的办法来恢复但是无极于终。我上百度去搜索,搜到了些眉目,我也进入了济南一家肠胃医院的网站。下面一幅图就是我咨询的聊天。那么你知道这种技术是怎么实现的吗?就是基本的网上聊天。还有一些咨询网站的客服聊天。
二 通信基本概念--实现网上聊天理论
计算机网络
①我们目的是为了写出一个后台聊天,为什么还要了解计算机网络呢?因为聊天的本质就是在计算机网络下进行的。
②何为计算机网络?通过百科搜索我们能查询到计算机网络其实就是一些相互连接的、以资源共享为目的的、自治的计算机的集合。通俗点讲就是计算机网络就像一个巨大的邮局,不同的计算机就像不同的信箱,通过电线或无线信号来传递信息。
③通信就要用各种协议比如早期的http协议和更加安全的Https协议(https经过加密和身份验证)。通信协议就像是一套规则和标准,确保计算机网络中的设备能够正确地发送和接收信息。它定义了数据如何被封装、地址信息如何被添加、以及错误如何被检测和纠正等。协议就是不同计算机遵循的规则。
④https和http只不过是应用层协议我们常见的两种。还有很多这里就不一一赘述。下面要讲的TCP,UDP是传输层的协议与我们今天要讲的聊天密切相关。
⑤每个计算机都有它的IP就是地址。有各自的IP我们才能传送数据。IPv6格式能分配的地址非常多据说可以为地球的每一粒沙子分配地址。
⑥端口就是用来区分每个软件或进程的。在下面代码中我们会用到。
⑦接下来的测试将在本地进行。要用到特殊地址127.0.0.1。
三 TCP
TCP实现聊天:分为客户端和服务端。客户端用来构造连接,发送信息。服务端用来接受信息,输出信息。
我们用TCP实现简单文字传输:
//客户端
package chat;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClientDemo1 {
public static void main(String[] args) {
try {
//获取服务端的地址
InetAddress serverIp = InetAddress.getByName("127.0.0.1");
int port = 9999;
//创见一个Socket连接
Socket socket = new Socket(serverIp, port); //一步化简--》 Socket socket = new Socket(InetAddress.getName(""), 5555);
//发送信息创建io流
OutputStream os=socket.getOutputStream();
os.write("你好".getBytes());
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//服务端
package chat;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//服务器端
public class TcpServerDemo1 {
public static void main(String[] args) {
ByteArrayOutputStream bao=null;
//地址 端口号
try {
ServerSocket serverSocket = new ServerSocket(9999);
//等待客户端连接过来
Socket socket=serverSocket.accept();
//读取客户端的信息
InputStream is=socket.getInputStream();
//管道流
bao=new ByteArrayOutputStream();
byte[]buffs=new byte[1024];
int len;
while((len=is.read(buffs))!=-1){
bao.write(buffs,0,len);
System.out.println(bao.toString());
//关闭
}
}catch(Exception e){
e.printStackTrace();
}
finally{
if(bao!=null) {
try {
bao.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
我们用TCP实现文件上传(与上面代码很是相似但略有不同):
//客户端
package file;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
//文件上传
public class TcpClientDemo2 {
public static void main(String[] args) {
try {
//获取连接
Socket socket=new Socket(InetAddress.getByName("127.0.0.1"),5555);
//文件输出--》创建一个输出流
OutputStream os=socket.getOutputStream();
//读取文件
FileInputStream fis=new FileInputStream(new File("C://Users//hp//OneDrive//图片//本机照片//微信图片_20240227182056.jpg"));
int len;
byte[]buffs=new byte[2014];
while((len=fis.read(buffs))!=-1){
os.write(buffs,0,len);//写进来再输出去
}
//写一个传送完成的标志,告诉服务器已经结束了
socket.shutdownOutput();
//当传送完成时应该输出语句输送成功
InputStream is=socket.getInputStream();
//管道输出
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
int len1;
byte[]buffs1=new byte[2024];
while((len1=is.read(buffs1))!=-1){
byteArrayOutputStream.write(buffs1,0,len1);
}
System.out.println(byteArrayOutputStream.toString());
byteArrayOutputStream.close();
is.close();
fis.close();
os.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//服务端
package file;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
public class TcpServerDemo2 {
public static void main(String[] args) {
try {
//服务端的端口
ServerSocket serverSocket=new ServerSocket(5555);
//等待接受,阻塞式监听会一直等待
Socket socket=serverSocket.accept();
//获取输入流
InputStream is=socket.getInputStream();
//文件输出
FileOutputStream fos=new FileOutputStream(new File("receive.jpg")); //命了个名
int len;
byte[]buffs=new byte[2024];
while((len=is.read(buffs))!=-1){
fos.write(buffs,0,len);//写进来输出
}
//输出输出完成
//输出流
OutputStream os=socket.getOutputStream();
os.write("输送成功".getBytes());
fos.close();
is.close();
socket.close();
serverSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
文件上传成功后,我们文件会出现在最下面如图所示:
四 UDP
既然上面已经通过TCP实现交流了为什么还要UDP实现交流呢?这不得不提一下两者的差别。TCP协议需要进行连接,而UDP协议不需要进行连接,随便传送。
//建立一个Socket
DatagramSocket socket=new DatagramSocket();
//建立一个数据包
String msg="新年快乐";
InetAddress localhost=InetAddress.getByName("localhost");
int port=5555;
DatagramPacket packet=new DatagramPacket(msg.getBytes(),msg.getBytes().length,localhost,port);
//发送数据包
socket.send(packet);
//关闭
socket.close();
//开发端口
DatagramSocket socket=new DatagramSocket(5555);
//接受数据包
byte[]buffs=new byte[1024];
DatagramPacket packet=new DatagramPacket(buffs,0,buffs.length);
socket.receive(packet);
System.out.println(packet.getAddress().getHostAddress());
System.out.println(new String(packet.getData(),0, packet.getLength()));
通过上面的代码可以发现:UDP在客户端先建立一个socket连接,建立包,发送包的过程。然而没有了服务端这一概念,不需要进行连接而是接受包输出包的过程。
由此我们可以实现互发消息,通过多线程。
//发送消息
package send;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class UdpSend implements Runnable{
DatagramSocket socket=null;
BufferedReader reader=null;
private int fromPort;
private String toIp;
private int toPort;
public UdpSend(int fromPort, String toIp, int toPort) throws Exception {
this.fromPort = fromPort;
this.toIp = toIp;
this.toPort = toPort;
socket=new DatagramSocket(fromPort);
reader=new BufferedReader(new InputStreamReader(System.in));
}
@Override
public void run() {
//准备数据控制台读取-->打包进去
while (true) {
try {
String data = reader.readLine();
byte[] datas;
datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress(this.toIp, this.toPort));
socket.send(packet);
if (data.equals("bye")) {
break;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
//发送
}
socket.close();
}
}
//接受消息
package send;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class UdpReceive implements Runnable{
DatagramSocket socket=null;
private int port;
private String msg;
public UdpReceive(int port,String msg) throws Exception {
this.port=port;
this.msg=msg;
socket=new DatagramSocket(port);
}
public void run(){
while(true) {
try {
//准备接受包裹
byte[] container = new byte[2024];
DatagramPacket packet = new DatagramPacket(container, 0, container.length);
//接受
socket.receive(packet);
//断开连接
int length = packet.getLength();
byte[] data = packet.getData();
String receiveD = new String(data, 0, length);
System.out.println(msg+":"+receiveD);
if (receiveD.equals("bye")) {
break;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
socket.close();
}
}
老师类:
package send;
public class tackTeacher {
public static void main(String[] args) throws Exception {
new Thread(new UdpSend(4444,"localhost",7777)).start();
new Thread(new UdpReceive(8888,"学生")).start();
}
}
学生类:
package send;
public class tackStudent {
public static void main(String[] args) throws Exception {
new Thread(new UdpSend(5555,"localhost",8888)).start();
new Thread(new UdpReceive(7777,"老师")).start();
}
}
五 URL
URL其实就相当于网络爬虫,下载网络视频音乐等。
这里是一段下载音乐的代码:
package U;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.*;
public class UrlDown {
public static void main(String[] args) throws Exception {
//下载地址
URL url=new URL("\n" +
"https://m804.music.126.net/20240601202251/50656d3a6d5b5489905b09e4ada8bef2/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/34873299362/7d37/4c2f/3640/245ede6e6294337d349d85532c0abcc3.m4a");
//连接到这个资源
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
//输入
InputStream is=connection.getInputStream();
FileOutputStream fos=new FileOutputStream("f.m4a");
byte[]buffs=new byte[1024];
int len;
while((len=is.read(buffs))!=-1){
fos.write(buffs,0,len);
}
//断开
fos.close();
is.close();
connection.disconnect();
}
}
如果包最下面出现如图情况就说明下载完成了。如果还有什么不懂的地方或者没有实现,可以私信我或在评论区留下您的问题。