网络编程概述
就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。
有人说,20世纪最伟大的发明不是计算机,而是计算机网络。哈哈,的确是这样,现在没有网,简直不能活下去。
计算机之间要进行通讯的话要以什么样的规则进行通信呢,这就是网络模型研究的问题,我们下来学习。
网络模型
- OSI参考模型
- TCP/IP参考模型
OSI参考模型
应用层
表示层
会话层
传输层
网络层
数据链路层
物理层
TCP/IP参考模型
应用层
传输层
网络层
主机至网络层
网络通信三要素
- IP地址:InetAddress
- 网络中设备的标识,不易记忆,可用主机名
- 端口号
- 用于标识进程的逻辑地址,不同进程的标识
- 传输协议
- 通讯的规则
常见协议:TCP,UDP
- 通讯的规则
IP地址
说起IP地址,我们每个人都知道自己的电脑有个IP地址,它在计算机中有什么作用呢?我们就来看一下它的具体概念
要想让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,也就是网络中计算机的唯一标识,通过这个标识号来指定要接受数据的计算机和识别发送的计算机,在TCP/IP协议中,这个标识号就是IP地址。
那么,我们如何获取和操作IP地址呢?java提供了一个类**InetAddress **供我们使用对IP地址的获取和操作。
我们来获取本机的主机名和IP地址
public class InetAddressDemo {
public static void main(String[] args) {
try {
InetAddress in = InetAddress.getLocalHost(); System.out.println(in.toString());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
运行程序,我们就得到了本机的主机名和IP地址
那么我们想要知道别人的IP地址或主机名怎么办呢?当然也是有方法的
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException { InetAddress address = InetAddress.getByName("192.168.2.102");
// public String getHostName()获取主机名,
String name = address.getHostName();
// public String getHostAddress()获取IP地址
String ip = address.getHostAddress();
System.out.println(name + "---" + ip);
}
}
如果你和别人在一个局域网内,知道了他的主机名或者IP地址就可以获取到另外一个。
端口号
端口号它分为两种,一种是物理端口,另外一种是逻辑端口。
物理端口就是网卡口,我们要学的呢就是逻辑端口,它是什么呢?
- 每个网络程序都会至少有一个逻辑端口
- 用于标识进程的逻辑地址,不同进程的标识
- 有效端口:065535,其中01024系统使用或保留端口。
TCP和UDP协议
TCP和UDP协议它们是通讯的规则,它们有什么区别呢?
TCP
建立连接,形成传输数据的通道
在连接中进行大数据量传输
通过三次握手完成连接,是可靠协议
必须建立连接,效率会稍低
UDP
将数据源和目的封装成数据包中,不需要建立连接
每个数据包的大小在限制在64k
因无连接,是不可靠协议
不需要建立连接,速度快
一般的软件它既有UDP,又有TCP,用TCP来保证软件的可靠性,用UDP来保证软件的传输速度快。
Socket
我们继续看Socket,我们说的网络编程也就是Socket编程也叫做网络套接字。
- Socket套接字:
- 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
- Socket原理机制:
- 通信的两端都有Socket。
- 网络通信其实就是Socket间的通信。
- 数据在两个Socket间通过IO传输。
UDP传输
我们要用UDP传输数据时,怎么用Socket建立连接呢?
- DatagramSocket与DatagramPacket
- 建立发送端,接收端。
- 建立数据包。
- 调用Socket的发送接收方法。
- 关闭Socket。
发送端与接收端是两个独立的运行程序。我们用代码实现一个UDP传输数据的例子
UDP传输-发送端
/*
* 需求:接收指定端口发送过来的数据
*
* UDP协议发送数据:
* A:创建发送端Socket对象
* B:创建数据,并把数据打包
* C:调用Socket对象的发送方法发送数据包
* D:释放资源
*/
public class SendDemo {
public static void main(String[] args) throws IOException {
// 创建发送端Socket对象
// DatagramSocket()
DatagramSocket ds = new DatagramSocket();
// 创建数据,并把数据打包
// DatagramPacket(byte[] buf, int length, InetAddress address, int port)
// 创建数据
byte[] bys = "UDP过来了".getBytes();
// 长度
int length = bys.length;
// IP地址对象
InetAddress address = InetAddress.getByName("192.168.2.102");
// 端口
int port = 12345;
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
// 调用Socket对象的发送方法发送数据包
// public void send(DatagramPacket p)
ds.send(dp);
// 释放资源
ds.close();
}
}
UDP传输-接收端
/* * UDP协议接收数据:
* A:创建接收端Socket对象
* B:创建一个数据包(接收容器)
* C:调用Socket对象的接收方法接收数据
* D:解析数据包,并显示在控制台
* E:释放资源
*/
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
// 创建接收端Socket对象
// DatagramSocket(int port)
DatagramSocket ds = new DatagramSocket(12345);
// 创建一个数据包(接收容器)
// DatagramPacket(byte[] buf, int length)
byte[] bys = new byte[1024];
int length = bys.length;
DatagramPacket dp = new DatagramPacket(bys, length);
// 调用Socket对象的接收方法接收数据
// public void receive(DatagramPacket p)
ds.receive(dp); // 阻塞式
// 解析数据包,并显示在控制台
// 获取对方的ip
// public InetAddress getAddress()
InetAddress address = dp.getAddress();
String ip = address.getHostAddress();
// public byte[] getData():获取数据缓冲区
// public int getLength():获取数据的实际长度
byte[] bys2 = dp.getData();
int len = dp.getLength();
String s = new String(bys2, 0, len);
System.out.println(ip + "传递的数据是:" + s);
// 释放资源
ds.close();
}
}
我们先运行接收端的代码,再运行发送端的代码,这样在接收端就会收到由发送端发过来的数据。完成了UDP传输
多线程UDP聊天
/*
* 通过多线程实现聊天程序,我们就要开启两个线程,一个接收数据,一个发送数据,这样我就可以实现在一个窗口发送和接收数据了
*/
public class ChatRoom {
public static void main(String[] args) throws IOException { DatagramSocket dsSend = new DatagramSocket();
DatagramSocket dsReceive = new DatagramSocket(12345); SendThread st = new SendThread(dsSend);
ReceiveThread rt = new ReceiveThread(dsReceive);
Thread t1 = new Thread(st);
Thread t2 = new Thread(rt);
t1.start(); t2.start();
}
}
/* * 接收数据 */
public class ReceiveThread implements Runnable {
private DatagramSocket ds;
public ReceiveThread(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try { while (true) {
// 创建一个包裹
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
// 接收数据 ds.receive(dp);
// 解析数据
String ip = dp.getAddress().getHostAddress();
String s = new String(dp.getData(), 0, dp.getLength()); System.out.println("from " + ip + " data is : " + s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/* * 发送数据 */
public class SendThread implements Runnable {
private DatagramSocket ds;
public SendThread(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
// 封装键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = br.readLine()) != null) {
if ("886".equals(line)) {
break;
}
// 创建数据并打包
byte[] bys = line.getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.2.102"), 12345);
// 发送数据
ds.send(dp);
}
// 释放资源
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
我们只需要运行聊天室ChatRoom类,就可以完成单窗口聊天了你发送一句,他就会接收一句,是不是很有意思呢?