目录
C、协议:数据在网络中传输的规则,常见的协议有UDP和TCP协议
概念:网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。
(简单来说:计算机之间的交互,实现通信的目的。)
网络编程的三要素:IP地址、端口、协议
由IP地址找到计算机、再由端口号找到具体的应用、在接收端按照规定好的协议把包进行解析
网络编程三要素:
A、IP地址:设备在网络中的地址,是唯一的表示
a. ipv4与ipv6
域名:www.baidu.com(实际上是通过DNS解析成ip地址返回给计算机)然后计算机再通过IP地址再去访问对应的服务器
(1)ipv4(4字节....32位)——但是只能满足42亿个服务器的使用(附:为了解决难以记忆的问题——使用 点分十进制)
(附:“点分十进制”是指现在网络中IPv4的IP地址的写法.由于这种IP地址是32位二进制,也就是4字节组成,但人们很难记忆,就用“点分十进制”来书写.即32个二进制,每一个字节单独转成一个十进制数,共4个十进制数,中间用点"."隔开.如:电脑中二进制IP:11001010 00101001 00001000 00010000 我们不好记,不好写,那么按上面的规则每一组转成一个十进制202 41 8 16写成202.41.8.16,就是我们生活中的IP地址了)
为了解决ipv4只能满足42亿个服务器的使用的问题——ipv6
(2)ipv6(16字节为一组(8组)——128位)
冒分十六进制表示法:IPV6地址的表示IPV6采用冒分十六进制记法(colon hexadecimal notation) , 它将128比特的IP地址以16个比特为单位进行划分, 每个单位用十六进制来表示, 各个单位之间用冒号分开。
0为压缩表示法 —— ::
只能去各个位置前面的0,不能去后面的0画红线部分
b.常用的命令:(WIN+R)
ipconfig:查看本机IP地址
ping+IP地址/域名:检查网络是否联通、也可以用于查看域名对应的IP地址为多少
附:特殊的IP地址 127.0.0.1 ——回送地址、也称本地回环地址,可以代表本机的ip地址,一般用于测试
c.JAVA中 【InetAddress】类的使用:
InetAddress类没有构造方法,但是由InetAddress类的静态方法geyByName就可以获取InetAddress类的对象
(static InetAddress)getByName:确定主机名称的IP地址;主机可以是机器地址,也可以是IP地址
(String)getHostName:获取此IP地址的主机名
(String)gerHostAddress:返回文本中显示的IP地址字符串
实例:
package UDP.danbo;
import java.net.InetAddress;
import java.net.UnknownHostException;
//端口的使用
public class duankou {
public static void main(String[] args) throws UnknownHostException {
// 1.获得Ip地址或局域网名
InetAddress zkf = InetAddress.getByName("ZKF");//此处可以是Ip地址或局域网名
// 2.主机地址、主机名
String hostAddress = zkf.getHostAddress();
String hostName = zkf.getHostName();
System.out.println(hostAddress+"------------"+hostName);
}
}
B、端口:应用程序在设备中唯一的标识
端口号:用两个字节表示的整数,取值范围 0~65535 (其中0~1023之间端口号用于一些知名的网络服务或应用)
注:一个端口号只能被一个应用程序使用。
C、协议:数据在网络中传输的规则,常见的协议有UDP和TCP协议
UDP协议:(User Datagram Protocol)(用户数据报协议) 面向无连接的通信协议 速度快,有大小限制,一次最多发生64K,数据不安全、易丢失 可用于传递音频/视频/普通数据等
TCP协议:面向链接协议的通信协议
速度慢,没有大小限制,数据安全
UDP:
UDP发送端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class wangluobiancheng_fasongduan {
// 第一次练习
public static void main(String[] args) throws IOException {
// 1直接创建发送码头
DatagramSocket ds=new DatagramSocket();
// 2.找箱子——字符数组、长度、地址()、端口号
String s ="发送给村长的礼物";
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
int port =10000;
DatagramPacket dp= new DatagramPacket(bytes,bytes.length,address,port);
// 3.码头发送箱子
ds.send(dp);
// 4.释放资源
ds.close();
}
}
DatagramSocket(byte[] buf,int length,InetAddress,int port)的解释说明
(将1.字符数组的 2.多少个元素 发送到 3.ip地址的 4.端口号上)
UDP接收端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class wangluobiancheng_jieshouduan {
public static void main(String[] args) throws IOException {
//1.找接受的码头ds
DatagramSocket ds = new DatagramSocket(10000);
//2.找箱子Pack(只用于接受——字符数组、长度)
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//3.码头接收数据在箱子里 ds.receive(dp)
ds.receive(dp);
//4.从箱子里获得 dp.getlentgh();
// int length = dp.getLength();
byte[] data = dp.getData();
System.out.println(new String(data,0,length));
//5.释放码头资源
ds.close();
}}
注:一:第4步中:获得DP(箱子)中的长度,后 用于26中(0,length)——限定字符数
二:new String(bytes):打印+将bytes转换成String 可以改写成下面的代码
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);//************
【练习】:
重复发送数据直到发送的是886;
死循环接收端
三种通讯方式:
1:单播
(以上实例就是单播)
2:组播.
组播地址:224.0.0.0~239.255.255.255
224.0.0.0~224.0.0.255.为预留的组播地址——我们只能从224.0.1.0开始使用
组播的发送端与单播类似:发送到所有连接上组播地址的计算机
发送端(ds、dp发送到某个组播地址、3ds.send(dp)、close)
package UDP.zubo;
import java.io.IOException;
import java.net.*;
//发送端
public class zubo_fasongduan {
public static void main(String[] args) throws IOException {
// 1
DatagramSocket ds =new DatagramSocket();
// 2
String s = "hello,组播";
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("224.0.1.0");//唯一的不同:地址不同
int port =10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
// 3
ds.send(dp);
// 4
ds.close();
}
}
接受端(Ms、ds、3.接收端电脑加入组播地址、ds.receive(dp)、打印、close)
package UDP.zubo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class zubo_jieshouduan {
public static void main(String[] args) throws IOException {
MulticastSocket ms = new MulticastSocket(10000);
//一、MS
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
// ms.joinGroup(InetAddress.getByName("224.0.1.0"));、
// 二、增加了一步加入组播
ms.joinGroup(InetAddress.getByName("224.0.1.0"));
ms.receive(dp);
// 4.获得数据、获得长度、sout
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println(new String(data,0,length));
ms.close();
}
}
//注:1第一步创建的是MulticastSocket
// 2.打印的是 new String ();转化为字符串形式
3:广播:发送给【路由器所有能连接上】的计算机
发送端:与单播的不同之处为:广播的发送地址为255.255.255.255
接收端与单播一摸一样
TCP协议:
TCP通信原理:TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象。
通信之前要保证连接已经建立。
通过Socket产生的IO流来进行网络通信。
客户端(发送)
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class kehuduan_fasong {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 10000);
OutputStream os = socket.getOutputStream();
os.write("helll".getBytes());
os.close();
socket.close();
}
}
服务器(接收)
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class fuwuqi_jieshou {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);
Socket accept = ss.accept();
InputStream is = accept.getInputStream();
int b;
while((b = is.read())!=-1){
System.out.println((char)b);
}
is.close();
accept.close();
}
}
一些需要注意的问题:
三次握手(了解) :
四次挥手(了解):
【练习1】:
客户端:发送数据,接收服务器反馈
服务器:接收数据,给出反馈
客户端
package TCP.practice1;
import java.io.*;
import java.net.Socket;
public class kehuduan {
public static void main(String[] args) throws IOException {
// 1.创建客户端Socket对象
Socket socket = new Socket("127.0.0.1",10000);
// 2.Socket的输出字节流
OutputStream os = socket.getOutputStream();
os.write("hello".getBytes());
// 直接将os.close关流会导致后面的is中的整个Socekt无法使用;
// 错误一:read阻塞、读不完——没有结束标记;
// 解决方案:socket.shutdownOutput;——仅仅关闭输出流并写一个介素标记,对socket没有任何影响
socket.shutdownOutput();
// 3.接受反馈的字节流(涉及中文,不能用)
// InputStream is = socket.getInputStream();
// int b;
// while ((b =is.read())!=-1){
// System.out.println((char)b);
// }
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// new InputStreamReader(socket.getInputStream())
// 1. InputStream is = socket.getInputStream();()相当于创建字节流
// 2. InputStreamReader将()内的字节流转化成字符流
// 循环
String line;
while ((line = br.readLine())!=null){
System.out.println(line);
}
// is.close();
br.close();
os.close();
socket.close();
}
}
服务器:
package TCP.practice1;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class fuwuqi {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);// 1. 创建服务器ServerSocket对象
Socket accept = ss.accept();// 2等待Sock连接
InputStream is = accept.getInputStream();// 3Socket的输入流+打印
// 错误一:read阻塞、读不完——没有结束标记;
// 解决方案:socket.shutdownOutput;——仅仅关闭输出流并写一个介素标记,对socket没有任何影响
int b;
while((b = is.read())!=-1)
System.out.print((char) b);
// 4.发出反馈(你谁呀)
A.错误例子(涉及中文不能用字节流)
// OutputStream os = accept.getOutputStream();
// os.write("你谁呀".getBytes());//前面当初字符串用
// 字节流改成字符流发送
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("你谁呀?");
bw.newLine();//z
bw.flush();//只调用close()方法,不调用flush()方法,不能写入文件里
// os.close();
is.close();
accept.close();
ss.close();
}
}
(注):
1.服务器的read在读客户端发来的消息时,如果没有识别到结束标记,就会阻塞 端口号输出流os后面要跟一个socket.shoudownOutput
2.中文不能使用字节流然后按单个char字符转换 中文不止一个的字符、会乱码
解决方法:将字节流转换为字符流的形式
发送中文那边:
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.write("你谁呀?");
bw.newLine();
bw.flush();
接收中文那边:
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = br.readLine())!=null){
System.out.println(line);
【练习二】:
将客户端的本地图片文件发送到服务器并保存
客户端:
package TCP.practice2;
import java.io.*;
import java.net.Socket;
//练习:
// 客户端:将本地文件上传到服务器。接收服务器的反馈
//服务器:接收客户端上传的文件,上传完毕之后给出反馈
public class kehuduan {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10000);
//本地的流,用于读取本地文件——字节缓冲流加速读取(读取本地文件用普通字节流)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\ZKF\\IdeaProjects\\untitled4\\tp\\tupian1.jpg"));
//上传到服务器——网络中的流socket.getInputStream或ocket.getOutputStream
OutputStream os = socket.getOutputStream();//网络中的流
BufferedOutputStream bos = new BufferedOutputStream(os);//用缓冲流加速读取
int b;
while((b =bis.read())!=-1){//执行读取本地文件
bos.write(b);//执行写到网络中的服务器中
}
socket.shutdownOutput();//关闭socket网络——bis、bos网络中的流同时关闭——read可以读取结束标记
//接收(中文)网络流:反馈成功1.创建(转化(网络流))
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//使用:循环读取
String line;
while((line = br.readLine())!=null){
System.out.println(line);
}
bis.close();
socket.close();
}
}
服务器:
package TCP.practice2;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class fuwuqi {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);//1创建
Socket accept = ss.accept();//2、等待连接
//(创建)网络中的流:从网络中读取(IN)accept.getInputStream()、用缓冲流加速new BufferedInputStream
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
//(创建)本地的IO流将读取的文件写到OUT本地文件(永久化保存)、并用缓冲流加速
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\ZKF\\IdeaProjects\\untitled4\\T1_wangluobiancheng\\src\\TCP\\practice2\\copy.jpg"));
int b;//【使用】判断是否读取——写出读取到的 b
while((b= bis.read())!=-1){
bos.write(b);
}
// (网络流——使用到accept.getOutputStream)给出反馈:上传成功——中文——1.将字节流的accept.getOutputStream()2.转换成OutputStreamWriter3缓冲字符流
// (创建)输出 缓冲Buffered 字符流Writer
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
/*使用*/bw.write("上传成功");
bw.newLine();
bw.flush();
accept.close();
ss.close();
bos.close();
}
}