黑马程序员——网络编程——网络编程概述,UDP协议,TCP协议

时间:2023-02-17 08:43:21
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一.网络编程


1.计算机网络与网络编程概述


A:计算机网络

是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接
起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共
享和信息传递的计算机系统。

B:网络编程

就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。


2.网络模型概述


A:网络模型概述

计算机网络之间以何种规则进行通信,就是网络模型研究问题。

网络模型一般是指
OSI(Open System Interconnection开放系统互连)参考模型
TCP/IP参考模型

B:两种重要的网络模型(图)
黑马程序员——网络编程——网络编程概述,UDP协议,TCP协议


3.网络编程(网络编程三要素概述)



A:IP地址:InetAddress
网络中设备的标识,一般使用主机名

B:端口号
用于标识进程的逻辑地址,不同进程的标识

C:传输协议
通讯的规则
常见协议:TCP,UDP


4.IP概述


A:IP概述

要想让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,
通过这个标识号来指定要接受数据的计算机和识别发送的计算机,在TCP/IP协
议中,这个标识号就是IP地址。

所谓IP地址就是给每个连接在Internet上的主机分配的一个32bit地址。按照
TCP/IP规定,IP地址用二进制来表示,每个IP地址长32bit,比特换算成字节,就
是4个字节。例如一个采用二进制形式的IP地址是"00001010000000000000000000000001",
这么长的地址,人们处理起来也太费劲了。为了方便人们的使用,IP地址经常被写
成十进制的形式,中间使用符号"."分开不同的字节。于是,上面的IP地址可以表
示为"10.0.0.1".

IP地址的这种表示法叫做"点分十进制表示法",这显然比1和0容易记忆得多。

B:IP地址的组成

IP地址 = 网络号码+主机地址

A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码
B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码

C:IP地址分类
A类 1.0.0.1---127.255.255.254

(1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)
(2)127.X.X.X是保留地址,用做循环测试用的。

B类 128.0.0.1---191.255.255.254

172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。

C类 192.0.0.1---223.255.255.254

192.168.X.X是私有地址

D类 224.0.0.1---239.255.255.254 

E类 240.0.0.1---247.255.255.254

D:特殊地址
127.0.0.1 回环地址,可用于测试本机的网络是否有问题. ping 127.0.0.1   


DOS命令 ipconfig:查看本机IP地址


xxx.xxx.xxx.0 网络地址
xxx.xxx.xxx.255 广播地址


5.InetAddress类的概述


InetAddress类表示互联网协议 (IP) 地址的抽象类,没有构造方法. 

InetAddress类的常见功能:

获取本地主机:
public static InetAddress getLocalHost() 

通过主机名称获取InetAddress的对象:
public static InetAddress getByName(String host)

返回IP地址值的字符串形式:
public String getHostAddress()

返回主机的名称:
public String getHostName()


示例:

<span style="font-family:FangSong_GB2312;font-size:18px;"><strong>package cn.blog;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Demo {


public static void main(String[] args) throws UnknownHostException {

//通过InetAddress的getLocalHost方法获取主机地址对象
InetAddress localHost = InetAddress.getLocalHost();
//通过InetAddress的getByName方法使用IP地址字符串获取主机地址对象
InetAddress inetAddress = InetAddress.getByName("192.168.40.127");
//通过主机地址对象获取主机的名称
System.out.println(localHost.getHostName());
//通过主机地址对象获取主句的字符串IP地址
System.out.println(localHost.getHostAddress());


}

}
</strong></span>



6.端口

物理端口: 网卡口

逻辑端口: 指的就是逻辑端口

a:每个网络程序都会至少有一个逻辑端口
b:用于标识进程的逻辑地址,不同进程的标识
c:有效端口:0~65535,其中0~1024系统使用或保留端口


7.协议


UDP协议:

将数据源和目的封装成数据包中,不需要建立连接,每个数据报的大小在
限制在64k,因无连接,是不可靠协议,不需要建立连接,速度快.

TCP协议:

建立连接,形成传输数据的通道,在连接中进行大数据量传输,通过三次握手
完成连接,是可靠协议,必须建立连接,效率会稍低.



8.Socket通信原理


A:Socket套接字概述:

在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都
打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务.

网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字.

B:Socket原理机制:

通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO传输。

C:UDP网络编程操作:

使用DatagramSocket数据套接字与DatagramPacket数据包完成数据的传输.


发送端完成步骤:

使用DatagramSocket数据套接字类建立发送端
创建数据(byte数组)
使用DatagramPacket数据包类建立数据包
调用Socket的发送方法
关闭Socket


接收端完成步骤:

使用DatagramSocket数据套接字类建立接收端
创建数据
使用DatagramPacket数据包类建立数据包
调用Socket的发送接收方法
关闭Socket

注意事项:发送端与接收端是两个独立的运行程序

案例:使用UDP完成数据传递

发送端

<span style="font-family:FangSong_GB2312;font-size:18px;"><strong>package cn.blog3;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class Demo_UDPsend {

/**
* UDP协议发送端
*/
public static void main(String[] args) throws SocketException, IOException {
//建立UDP服务,发送端不需要指定端口,系统会自动分配一个
DatagramSocket ds = new DatagramSocket();

//定义数据内容
String s = "i love java";
//创建数组存储数据
byte[] buf = s.getBytes();
//获取数组长度
int length = buf.length;
//明确主机
InetAddress localHost = InetAddress.getLocalHost();
//明确端口
int port = 60000;
//将数据内容封装成数据包
DatagramPacket dp = new DatagramPacket(buf, 0, length, localHost, port);

//通过UDP的Socket服务中的功能完成数据的发送
ds.send(dp);
//关闭发送端资源
ds.close();
}

}
</strong></span>

接收端

<span style="font-family:FangSong_GB2312;font-size:18px;"><strong>package cn.blog3;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Demo_UDPreceive {

/**
* UDP协议接收端
*/
public static void main(String[] args) throws IOException {
//定义Socket服务并监听一个接口,明确接收端处理的应用程序
DatagramSocket ds = new DatagramSocket(60000);

//预先定义数组接收数据
byte[] buf = new byte[1024];

//获取数组长度
int length = buf.length;

//创建数据接收包
DatagramPacket dp = new DatagramPacket(buf, length);
//使用Socket服务中的receive方法将接收到数据存储到数据包
ds.receive(dp);

//通过数据包对象获取发送端的IP对象
InetAddress address = dp.getAddress();
//获取IP对象的字符串名称
String hostName = address.getHostName();

//将数据包转化为数组
byte[] buf2 = dp.getData();

//获取长度
int len = dp.getLength();

//输出获取到的数据
System.out.println("来自-"+hostName+"-传来的数据是:"+new String(buf2, 0, len));
//关闭接收端
ds.close();
}

}
</strong></span>



D:TCP网络编程操作:

通过使用Socket客户端和ServerSocket服务器端完成链接及数据的传输

客户端完成步骤:

建立客户端
建立连接后,通过Socket中的IO流(Socket流)进行数据的传输
关闭socket




服务器端完成步骤:
建立服务器端
建立连接后,通过ServerSocket获取Sokect然后通过Socket中的IO流(Socket流)进行数据的传输
关闭socket



注意事项:
a.客户端与服务器端是两个独立的应用程序
b.服务器端开启后等待客户端访问,不应关闭
c.一个服务器端对应多个客户端
d.不同客户端间通信可以通过服务器端中转信息


常见问题:
客户端连接上服务端,两端都在等待,没有任何数据传输?

因为read方法或者readLine方法是阻塞式,需要自定义结束标记

使用Socket中的shutdownInput,shutdownOutput方法解决等待


案例:使用TCP完成文件上传(服务器端接收完成后响应)


客户端

<span style="font-family:FangSong_GB2312;font-size:18px;"><strong>package cn.blog3;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;


public class Demo_Client {

/**
* 使用TCP协议通过客户端向服务器上传文件
* 创建客户端
*/
public static void main(String[] args) throws IOException {

//创建源文件对象
File file = new File("a.txt");

//获取主机IP
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost.getHostName());
//建立客户端的Socket服务,并进行目的地址链接
Socket sc = new Socket(localHost.getHostName(), 60000);

//获取客户端socket的IO字节输出流对象
OutputStream os = sc.getOutputStream();
//将字节流输出对象转换为字符流
OutputStreamWriter osw = new OutputStreamWriter(os);
//将字符流对象包装为缓冲区的字节流
BufferedWriter bw = new BufferedWriter(osw);

//创建输入流获取文件内容
BufferedReader br = new BufferedReader(new FileReader(file));

//读取文件内容写入SocketIO流中
String line;
while ((line= br.readLine())!=null) {
bw.write(line);
//换行
bw.newLine();
//刷新
bw.flush();
}
//文件读取完毕后关闭输出流
sc.shutdownOutput();

//使用socketIO输入流获取服务器的响应数据创建输入流读取数据
InputStream inputStream = sc.getInputStream();
InputStreamReader isr = new InputStreamReader(inputStream);
BufferedReader br2 = new BufferedReader(isr);
//输出服务器响应的数据
System.out.println(br2.readLine());

//关闭客户端
sc.close();


}

}
</strong></span>

服务器端

<span style="font-family:FangSong_GB2312;font-size:18px;"><strong>package cn.blog3;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Demo_Server {

/**
* 创建TCP服务器
*/
public static void main(String[] args) throws IOException {

//创建服务器对象,监听一个端口
ServerSocket ss = new ServerSocket(60000);
//通过Socket服务的accept方法获取服务器端的socket对象
Socket socket = ss.accept();
//获取服务器socketIO输入流,读取客户端传来的数据
InputStream inputStream = socket.getInputStream();

//将基本流包装为缓冲流
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));

//创建输出流存储数据
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
//读取客户端传来的数据
String line;
while ((line= br.readLine())!=null) {
bw.write(line);
//换行
bw.newLine();
//刷新
bw.flush();
}
//创建服务器响应机制
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bw2 = new BufferedWriter(new OutputStreamWriter(outputStream));

bw2.write("文件已经复制完成!!!");
bw2.flush();

//关闭服务器
socket.close();
}

}
</strong></span>