一、网络编程概述
1.概念
1、网络:计算机网络,由在不同地理位置、不同的计算机主机,互联形成的一个计算机系统。有通讯和数据共享的作用。
2、网络编程:在已经拥有完备成熟的网络系统之后,在整个基础上,使用网络进行编程,对应用层进行设计的活动。
2.目的
二、网络编程三要素
1、在网络编程中,必须要使用的三个基本的通信数据
2、IP地址、端口号、通信协议
(1)IP地址:网络中每一台计算机的唯一标识,通过IP地址找到指定的计算机。
(2)端口:用于标识进程的逻辑地址,通过端口找到指定进程。
(3)协议:定义通信规则,符合协议则可以通信,不符合不能通信。
1.TCP/IP
1.1.IP地址
1、在一个计算机网络中,某台计算机在网络中的唯一标志
2、分类:
(1)IPv4:192.168.2.84
使用4个0-255的数字,来表示一个ip地址,32位,2^32个地址,40亿四个字节中,可能有2个字节或者3个字节表示所在的子网剩余的部分是在子网中的IP号码
在一个子网中,使用一个字节表示,0-255 0表示子网的网号:192.168.2.0就表示当前的子网网号 255表示广播地址(在整个子网中的所有地址,都会接收到发送到广播地址的数据)特殊的IP地址:127.0.0.1,表示本地回环地址,表示当前正在运行这个程序的Ip相关的命令:ipconfig(查询当前网卡信息) ping(查看某个IP是否联通)
(2)IPv6:
由8组数字组成,每组数字都是4个16进制数(每个数字16种状态,32数字)
(3)127.0.0.1: 本机 localhost
TCP/IP 参考模型
总结:
- 网络编程中有两个主要的问题
如何准确的定位到网络上的一台或者多台主机
找到主机之后如何进行通信- 网络编程中的要素
IP和端口号 IP
网络通信协议 udp,tcp- 万物皆对象
/**
* @author Daniel
* 测试IP
*/
public class TestIndress {
public static void main(String[] args) {
/**
* 1、用于描述ip地址的对象所属的类型(主机名称、ip地址)
* 2、获取方式:
* getByName(String host): 根据主机名称获取当前类型对象
* getByAddress(byte[] arr):根据ip地址的字节数组获取当前类型对象
* getAllByName(String host):根据主机名称获取的所有当前类型对象的数组
* getLocalHost():获取当前主机的当前类型对象
* 3、对象的常用方法:
* getHostName():获取主机名称
* getAddress():获取ip地址的字节数组
* toString():同时获取主机名称和ip地址的字符串表示
*/
try {
//查询本机地址
InetAddress inetAddress1 = InetAddress.getByName ( "127.0.0.1" );
System.out.println (inetAddress1);
InetAddress inetAddress2 = InetAddress.getByName ( "localhost" );
System.out.println (inetAddress2);
//查询网站ip地址
InetAddress inetAddress3 = InetAddress.getByName ( "www.baidu.com" );
System.out.println (inetAddress3);
InetAddress localHost = InetAddress.getLocalHost ();//域名或自己电脑的名字
System.out.println (localHost);
System.out.println ( inetAddress2.getAddress () );//IP
System.out.println ( inetAddress2.getCanonicalHostName () );//规范的名字
System.out.println ( inetAddress2.getHostAddress () );//域名或自己电脑的名字
} catch (UnknownHostException e) {
e.printStackTrace ();
}
}
}
运行结果为:
1.2.端口号
1、也是一个数字,就是用于标记在电脑中的某个进程
2、使用两个字节来表示端口号:0-65535
也就是说,在计算机中,同时运行着的进程,最多只能有65536个
当程序运行时,需要有一个端口号,在程序运行结束之后,端口号被收回
3、在网络程序中,先在网络中通过ip地址,找到计算机,然后通过端口号找到对应的进程。
4、分配:在程序启动的时候,可以使用程序中指定的端口号,也可以随机分配
5、常用的端口号:
操作系统:0-1024之间
公有端口:0-1023
HTTP:80
HTTPS:443
FTP:21
MySQL:3306
Oracle:1521
Tomcat:8080
netstat -ano #查看所有的端口
netstat -ano | findstr "5900" #查看指定的端口
tasklist | findstr "8696" #查看指定端口的进程 如qq
快捷打开任务管理器 :Ctrl+Shift+Esc
/**
* @author Daniel
* InetSocketAddress
*/
public class InetSockTest {
public static void main(String[] args) {
InetSocketAddress inetSocketAddress1 = new InetSocketAddress ( "127.0.0.1", 8080 );
System.out.println (inetSocketAddress1);
InetSocketAddress inetSocketAddress2 = new InetSocketAddress ( "localhost",8080 );
System.out.println (inetSocketAddress2);
System.out.println ( inetSocketAddress1.getPort () );
System.out.println ( inetSocketAddress1.getHostName () );
}
}
运行结果为:
2.通信协议
TCP & UDP 对比
TCP:打电话
连接,稳定
三次握手 & 四次挥手
- 最少需要三次,保证稳定连接!
- A:你瞅啥?
- B:瞅你咋地?
- A:立新湖干一场!
- A:我要走了!
- B:我真的要走了吗?
- B:你真的真的要走了吗?
- A:我真的要走了!
客户端、服务端
传输完成,释放连接,效率低
UDP:发短信
不连接,不稳定
客户端、服务端:没有明确的界限
不管有没有准备号,都可以发给你……
如:导弹攻击
DDOS:洪水攻击!(饱和攻击)
3.TCP编程
1、使用的通信点就是Socket类型
2、客户端和服务端获取Socket对象的区别:
(1)客户端使用Socket的构造方法,创建一个Socket对象
(2)服务端不能使用自己创建的方式,而是使用服务端一个特殊的对象ServerSocket,接收客户端发来的请求,生成一个为这个客户端服务的Socket对象
3、构造方法:
Socket(InetAddress ip, int port):建立一个通信点,专门用于和ip主机的port程序进行通信。
只要这个对象创建成功了,就说明这个连接已经建立起来了,就说明当前的客户端已经联系上服务端了,已经获取了服务端返回的响应。
在创建对象的过程,就是在请求和服务端连接的过程。
4、服务端获取Socket对象的方式:
(1)启动一个服务程序,类型是ServerSocket,可以接收客户端发来的连接请求,一旦接收到请求,就可以创建一个和当前客户端交互的Socket对象
(2)ServerSocket的构造方法
ServerSocket(int port):创建一个服务端Socket对象,等待访问port端口的客户端
(3)accept():接收一个客户端发来的请求,返回一个服务此客户端的Socket对象
5、获取客户端和服务端的连接
(1)两个方法:
InputStream getInputStream():获取Socket对象的网络输入流
OutputStream getOutputStream():获取Socket对象的网络输出流
(2)一旦获取了输入输出流,就可以通过I\O的方式,来操作网络数据的传输。
(3)对应关系:
客户端的网络输入流,对应服务端的网络输出流
客户端的网络输出流,对应服务端的网络输入流
6、TCP编程步骤
客户端:
(1)创建Socket对象,建立和服务端的连接
(2)获取网络输入流和网络输出流
(3)通过I\O的操作来进行数据传输
服务端:
(1)创建ServerSocket对象,开启服务器,监听指定端口
(2)调用accept方法,接收客户端发来的请求,返回一个Socket对象
(3)获取服务端的网络输入流和网络输出流
(4)通过I\O的操作来进行输出传输
7、TCP编程加强:
(1)让客户端也接收数据,服务端也发送数据
(2)让字节流进行加强,转成字符流,加强成缓冲字符流
(3)让服务端多线程,同时可以处理多个用户的请求
TCP实现聊天
/**
* @author Daniel
* 服务端
*/
public class ServerTcpDemo {
public static void main(String[] args) {
ServerSocket socket = null;
Socket accept = null;
InputStream is = null;
ByteArrayOutputStream bos = null;
try {
//1.我得有一个地址
socket = new ServerSocket ( 9999 );
while(true){
//2.等待客户端连接过来
accept = socket.accept ();
//3.读取客户端信息
is = accept.getInputStream ();
//管道流
bos = new ByteArrayOutputStream ();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read (buffer))!= -1) {
bos.write ( buffer, 0, len );
}
System.out.println (bos.toString ());
}
} catch (IOException e1) {
e1.printStackTrace ();
}finally {
if(bos != null){
try {
bos.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
if(is != null){
try {
is.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
if(accept != null){
try {
accept.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
if(socket != null){
try {
socket.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
}
}
}
/**
* @author Daniel
* 客户端
*/
public class ClientTcpDemo {
public static void main(String[] args) {
InetAddress serverIp = null;
Socket socket = null;
OutputStream out = null;
try {
//1.要知道服务器的地址 端口
serverIp = InetAddress.getByName ( "127.0.0.1" );
int port = 9999;
//创建一个socket连接
socket = new Socket (serverIp,port);
out = socket.getOutputStream ();
//发送socketIo流
out.write ( "欢迎来Daniel的博客学习".getBytes () );
} catch (Exception e) {
e.printStackTrace ();
}finally {
if(out != null){
try {
out.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
if(socket != null){
try {
socket.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
}
}
}
运行结果显示(先开启服务端再开启客户端)
TCP实现传输文件
(1)先准备要传输的图片,如下(放根目录下):
(2)写客户端,服务端
/**
* @author Daniel
* 客户端
*/
public class FileTcpClientDaniel {
public static void main(String[] args) throws Exception {
//1.创建一个Socket连接
Socket socket = new Socket ( InetAddress.getByName ( "127.0.0.1" ), 2024 );
//2.创建一个输出流
OutputStream os = socket.getOutputStream ();
//3.读取文件
FileInputStream fis = new FileInputStream ( new File ( "1.jpg" ) );
//4.写出文件
int len;
byte[] bytes = new byte[1024];
while ((len = fis.read ( bytes ))!= -1){
os.write ( bytes,0,len );
}
//通知服务器我已经结束了
socket.shutdownOutput ();//我已经传输完了!
//确定服务器接收完毕,才能够断开连接
InputStream inputStream = socket.getInputStream ();
ByteArrayOutputStream bos = new ByteArrayOutputStream ();
byte[] bytes1 = new byte[1024];
int len1;
while ((len1 = inputStream.read ( bytes1 ))!= -1){
bos.write (bytes1,0,len1 );
}
System.out.println (bos.toString ());
//关闭资源
inputStream.close ();
bos.close ();
fis.close ();
os.close ();
socket.close ();
}
}
/**
* @author Daniel
* 服务端
*/
public class FileTcpServerDaniel {
public static void main(String[] args) throws Exception{
//1.创建服务
ServerSocket socket = new ServerSocket ( 2024 );
//2.监听客户端的连接
Socket accept = socket.accept ();
//3.获取输入流
InputStream is = accept.getInputStream ();
//文件输出
FileOutputStream fos = new FileOutputStream ( new File ( "66.jpg" ) );
int len;
byte[] bytes = new byte[1024];
while ((len =is.read ( bytes ))!= -1){
fos.write ( bytes,0,len );
}
//通知客户端我接收完毕了
OutputStream outputStream =accept.getOutputStream ();
outputStream.write ( "我已经接收到了,你可以断开连接了".getBytes () );
//关闭资源
fos.close ();
is.close ();
accept.close ();
socket.close ();
outputStream.close ();
}
}
(3)先运行服务端,再运行客户端,运行结果显示目录下多出一个文件
4.UDP编程
1、使用的Socket是:DatagramSocket
2、构造方法:
DatagramSocket():不指定端口号,创建通信点,端口号随机分配,一般用于发送端
DatagramSocket(int port):指定端口号,创建通信点,一般用于接收端
3、成员方法:
send(DatagramPacket dp):将一个dp数据报包发送
receive(DatagramPacket dp):将数据接收到dp参数中
4、DatagramPacket介绍:
1、表示一个数据报数据的封装对象的类型
2、构造方法:
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
buf:要发送的数据的字节数组
offset:从数组的哪个位置开始发送
length:发送多少数据
address:发送到哪个ip
port:发送到哪个程序
3、常用成员方法:
getData():返回该数据包中的字节数组
getLength():返回该数据包中接收到的字节个数
5、UDP编程的步骤:
发送端:
1、使用的Socket是:DatagramSocket
2、构造方法:
DatagramSocket():不指定端口号,创建通信点,端口号随机分配,一般用于发送端
DatagramSocket(int port):指定端口号,创建通信点,一般用于接收端
3、成员方法:
send(DatagramPacket dp):将一个dp数据报包发送
receive(DatagramPacket dp):将数据接收到dp参数中
4、DatagramPacket介绍:
1、表示一个数据报数据的封装对象的类型
2、构造方法:
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
buf:要发送的数据的字节数组
offset:从数组的哪个位置开始发送
length:发送多少数据
address:发送到哪个ip
port:发送到哪个程序
3、常用成员方法:
getData():返回该数据包中的字节数组
getLength():返回该数据包中接收到的字节个数
5、UDP编程的步骤:
发送端:
(1)准备通信点对象
(2)准备发送的包裹对象
(3)调用通信点的发送方法
接收端:
(1)准备通信点对象
(2)准备接收端接收的容器
(3)调用通信点的接收方法
(4)解析接收到的数据准备通信点对象
(5)准备发送的包裹对象
(6)调用通信点的发送方法
接收端:
(1)准备通信点对象
(2)准备接收端接收的容器
(3)调用通信点的接收方法
(4)解析接收到的数据
//UDP编程 发送端
public static void main(String[] args) throws IOException {
// 创建通信点
DatagramSocket ds = new DatagramSocket();
byte[] b = "你好,我是周杰伦".getBytes();
int len = b.length;
InetAddress lh = InetAddress.getLocalHost();
byte[] as ={(byte)192,(byte)168,2,84};
byte[] a ={127,0,0,1};
InetAddress ll = InetAddress.getByAddress(a);
// System.out.println(lh.toString());
//创建数据包
DatagramPacket dp = new DatagramPacket(b, 0, len, ll, 9999);
//调用send方法
ds.send(dp);
ds.close();
}
}
public class ClientUdp {
//udp接收端
public static void main(String[] args) throws IOException {
//创建通信点
DatagramSocket ds = new DatagramSocket(9999);
//创建一个数组
byte[] bs = new byte[1024];
int len = bs.length;
//创建一个接受包
DatagramPacket dp = new DatagramPacket(bs, len-1);
//接受数据
ds.receive(dp);
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println(new String(data,0,length));
}
}
运行结果为:
5.URL
统一资源定位符:定位资源的,定位互联网上的某一个资源
DNS域名解析 www.baidu.com xxx.x…x…x
协议://ip地址:端口/项目名/资源
/**
* @author Daniel
* url
*/
public class UrlDaniel {
public static void main(String[] args) throws Exception {
URL url = new URL ( "https://localhost:8080/index/jsp?username=Daniel&password=123" );
System.out.println ( url.getProtocol () );//协议
System.out.println ( url.getPort () );//端口
System.out.println ( url.getPath () );//文件
System.out.println ( url.getHost () );//主机ip
System.out.println ( url.getQuery () );//参数
System.out.println ( url.getFile () );//全路径
}
}
运行结果为: