计算机网络
将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统
网络模型
OSI(Open System Interconnection 开放系统互连)七层参考模型
物理层:主要定义物理设备标准。
数据链路层:主要将从物理层接收的数据进行MAC地址的封装与解封装。通常将该层的数据叫做帧,数据通过交换机来传输。
网络层:主要将从下层接收到的数据进行IP地址的封装与解封装。该层的数据叫做数据包,工作的设备是路由器。
传输层:定义了一些传输协议和端口号。
会话层:通过传输层建立数据传输的通路。
表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(把计算机能够识别的东西转换成人能够识别的东西)
应用层:主要是一些终端的应用。
IP地址
InetAddress:网络中的设备表示,类似于计算机的身份证号
IP地址的组成
IP地址=网路地址+主机地址
IP地址分类
A类IP地址:第一段号码为网络地址,剩下三段为本地计算机号码
B类IP地址:前两段号码为网络地址,剩下两段为本地计算机号码
B类IP地址:前三段号码为网络地址,剩下一段为本地计算机号码
特殊地址
127.0.0.1 回环地址,用于测试本机的网络是否有问题
DOS命令 ipconfig:可查看本机的IP地址
xxx.xxx.xxx.255 广播地址
端口
用于标识进程的逻辑地址,不同进程的端口号不同
物理端口:网卡口
逻辑端口:每个程序都有一个逻辑端口,有效端口0~ 65535,其中0~1023是系统使用或保留的端口
协议
UDP
将数据源与数据封装在数据包中,不需要建立连接,属于不可靠协议,速度快。
每个数据包限制大小为64k
TCP
建议连接,形成传输数据的通道,属于可靠协议,效率低。
在连接中进行大量数据传输
InetAddress类
用于获取IP地址并进行操作,Java提供InetAddress类
InetAddress类的常见功能
public static InetAddress getByName(String host) 通过主机名获取主机的IP地址
public String getHostAddress() 获取IP
public String getHostName() 获取主机名
getLocalHost();
Socket类
Socket原理:
通信两端都有Socket,网络间的通信其实就是Socket间的通信,数据在Socket间通过IO流进行传输
UDP协议发送数据
创建客户端
public class SocketTest {
public static void main(String[] args) throws IOException {
//创建客户端UDP的Socket
DatagramSocket ds=new DatagramSocket();
//封装数据
//DatagramPacket( byte[] buf, int length, InetAddress address,int port)
//构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
//创建数据包
byte[] bytes="PlkoNya".getBytes();
//获取本机的ip(两种形式获取)
String s=InetAddress.getByName("PlkoNya").getHostAddress();
byte[] add = InetAddress.getByName("PlkoNya").getAddress();
System.out.println(s);
//获取本机的IP地址并以字符串的形式输出
System.out.println(InetAddress.getLocalHost().getHostAddress());
//服务器的ip 因为服务器就是本机,所以将本机的IP传入数据报包中
InetAddress address=InetAddress.getByAddress(add);
//port是服务端的端口号 数据包中的参数1,数据存放的byte数组,参数2,数据存放的数组的长度,参数3,发送的主机ip,参数4,该主机上的端口号
DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,9999);
//发送数据包
ds.send(dp);
//释放资源
ds.close();
}
}
创建服务器
运行的时候需要先开启服务器,然后再打开客户端发送文件。
public class UDPServer {
public static void main(String[] args) throws IOException {
//创建服务端 DatagramSocket( int port) 创建服务端的Socket并暴露端口号
DatagramSocket ds=new DatagramSocket(9999);
//创建空的数据包,用于接收数据包 DatagramPacket( byte[] buf, int length)
byte[] bytes=new byte[1024];
DatagramPacket dp=new DatagramPacket(bytes,bytes.length);
//接收数据
System.out.println("服务器开启,等到接收数据");
ds.receive(dp);//阻塞的方法,如果服务器开启后,没有数据传输过来,就会一直阻塞
//获取数据包的数据
byte[] data=dp.getData();
//获取数据包中的数据的实际长度
int lenth=dp.getLength();
//获取发送方的IP
String ip=dp.getAddress().getHostAddress();
//将字节数组转换成字符串
String s=new String(data,0,lenth);
System.out.println(ip+"给你发来消息:"+s);
//释放资源
ds.close();
}
}
TCP协议传输数据
需要创建客户端与服务器建立双方的连接通道
客户端
public static void main(String[] args) throws IOException {
//创建客户端的Socket
//创建一个流套接字并将其连接到指定IP地址的指定端口号
Socket socket = new Socket("192.168.43.74", 9999);
//获取通道中的输出流
OutputStream out=socket.getOutputStream();
//发送数据
out.write("Nya".getBytes());
//释放资源
socket.close();
}
}
服务器
public class TCPServer {
public static void main(String[] args) throws IOException {
//创建服务端的Socket并暴露端口号
ServerSocket ss = new ServerSocket(9999);
System.out.println("服务器开启,等待连接。。。");
//侦听客户端的连接 阻塞式方法,在方法在连接传入前一直阻塞
Socket accept = ss.accept();
//获取通道中的输入流
InputStream in = accept.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
//转换成字符串
String s=new String(bytes,0,len);
System.out.println(s);
//关闭服务器
ss.close();
}
}
TCP键盘录入数据并在服务器上将数据记录在文件中
客户端
public class Client {
public static void main(String[] args) throws IOException {
Socket client = new Socket("192.168.43.74",8888);
OutputStream clientOut = client.getOutputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientOut));
String msg = null;
while (true){
System.out.println("请输入消息:");
if ((msg=br.readLine())!=null){
bw.write(msg);
bw.newLine();
bw.flush();
if(msg.matches("8+")){
client.shutdownOutput();
client.close();
break;
}
}
}
}
}
服务器
服务器可以在文件中记录消息日志文件。哪个IP在何时发的什么消息。
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
BufferedWriter bw = new BufferedWriter(new FileWriter("msg.txt",true));
bw.newLine();
System.out.println("服务器已开启,等待连接...");
Socket link = server.accept();
System.out.println("客户端IP地址:"+link.getInetAddress().getHostAddress()+"已连接");
BufferedReader br = new BufferedReader(new InputStreamReader(link.getInputStream()));
String msg=null;
Date date = new Date();
SimpleDateFormat sdp = new SimpleDateFormat("yyyy-MM-dd HH:mm");
while ((msg=br.readLine())!=null){
date.setTime(System.currentTimeMillis());
String log=link.getInetAddress().getHostAddress()+" "+sdp.format(date)+"发送消息文件:";
bw.write(log);
bw.flush();
bw.write(msg);
bw.flush();
bw.newLine();
}
}
}
TCP多线程上传文件
服务器(将上传文件功能交给其他类)
public class Server {
public static void main(String[] args) throws IOException {
//创建服务端
ServerSocket ss = new ServerSocket(6666);
System.out.println("服务器开启,等待连接....");
//一个服务端,连接多个客户端
//侦听通道
int i=1;
while (true){
Socket accept = ss.accept();
System.out.println((i++)+"个客户已经连接");
new UpLoadThread(accept).start();
}
}
}
该类实现上传文件功能
public class UpLoadThread extends Thread {
private Socket socket;
public UpLoadThread(Socket socket) {
this.socket=socket;
}
@Override
public void run() {
try {
//获取通道中的输入输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
//多个客户端上传文件。防止文件覆盖现象,取随机文件名
FileOutputStream fileout = new FileOutputStream(System.currentTimeMillis() + "temp");
int temp;
byte[] bytes=new byte[1024];
while (((temp=in.read(bytes))!=-1)){
fileout.write(bytes,0,temp);
}
//客户端上传完毕,服务端需要给客户端反馈
out.write("上传成功!".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端(其余客户端实现功能一样,只是上传文件的不同而已)
public class Client01 {
public static void main(String[] args) throws IOException {
//创建客户端
Socket Client=new Socket("192.168.43.74",6666);
//获取通道中的输入流输出流
InputStream in = Client.getInputStream();
OutputStream out = Client.getOutputStream();
//客户端读取文件的流
FileInputStream filein = new FileInputStream("D:\\Test\\IO类继承关系图.jpg");
byte[] bytes=new byte[1024];
int temp;
while ((temp=filein.read(bytes))!=-1){
out.write(bytes,0,temp);
out.flush();
}
//客户端传递完毕
Client.shutdownOutput();
//读取服务端的反馈
byte[] rebytes=new byte[1024];
int len = in.read(rebytes);
String msg=new String(rebytes,0,len);
System.out.println(msg);
//释放资源
Client.close();
filein.close();
}
}