网络编程:通过计算机语言实现资源的共享
网络编程模型
数据一层层的封装打包
应用层:eg:应用程序,qq
表示层:
会话层:
传输层:
网络层:数据传输
数据链路层:数据帧,使用交换机传递数据
物理层 : 将数据转化为1,0数据
应用程序:网络编程+IO+多线程
此博客的主角是网路层
java针对网络编程提供的类都在java.net下面
网络编程的要素
A:IP地址 找到对应的应用程序 B:端口号 对应的应用程序的标识 C:协议 通过某个规则协议进行
IP地址:是每台计算机在网络中的唯一标识
eg:192.1668.32.80 注意: 计算机在网络中的唯一标识肯定不是这样的: 所以得转化成二进制的数据,计算机才能够识别: 11000000 10101000 00100000 01010000
那为什么每次我们配置ip地址不配成二进制的?
因为二进制的数据我们并不常用,且不方便记忆,并推出了记忆ip地址的方案:“点分十进制”
ip地址的组成:
网络号+主机端号
IP地址的分类:
A:0.0.0.0~127.255.255.255 B:128.0.0.0~191.255.255.255 C:192.0.0.0~223.255.255.255 D:不常见 E:不常见
A类:第一段表示网络号段,后三段表示主机号码
网络号码:256*256*256 16777216(可以给这么多的计算机使用) 稀少:一般是国家使用,eg 军队 电信
B类:前两段表示网络号段,后两端表示主机号码
网络号码:256*256 65536 eg:大学校园网
C类:前一段表示网络号段,后三段表示主机号码
网络号码:256 eg:家庭,
局域网IP地址的常见配置
192.168.x.x (常见) 10.x.x.x (一般公司开头)
特殊地址:
x.x.x.0 网络号 x.x.x.255 广播号
InetAddress
package com.net;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 如果一个类没有构造方法是什么情况?
* 1:单例模式
* 2:类中的成员都是静态的(Arrays,Math,Collections)
* 3:通过一个静态方法返回本身对象。
* class Demo{
* private Demo();
* public static Demo getDemo(){
* return new Demo();
* }
* }
* @author yuliyang
* @version $Id: InetAddressDemo.java, v 0.1 2016年11月21日 下午10:03:43 yuliyang Exp $
*/
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
//根据主机名获取到IP地址对象
//InetAddress address = InetAddress.getByName("yly");
InetAddress address = InetAddress.getByName("192.168.31.223");
System.out.println(address);
//获取主机名
String hostNam = address.getHostName();
//获取IP地址
String ipAddress = address.getHostAddress();
System.out.println(hostNam + "---" + ipAddress);
}
}
端口号:每一个进程的逻辑地址,是一个标识号
一个进程是一个应用程序,,所以,我们说端口号也是一个应用程序的标识号范围
0-65535之间 0-1024之间不要随意使用,因为它被保留或者被系统进程占用,
协议
通信的规则 UDP(效率):把数据打包,不建立连接,导致数据不可靠,且数据有限制,64k=32768个汉字,但是速度快效率高。 TCP(安全):建立连接通道,三次握手协议,只要通道没有断开,数据没有限制,数据可靠,但是耗时速度慢, 一般的应用程序又有UDP(类似于群聊)又有TCP(类似于单聊)协议
1:简单的UDP代码
send端
:
package com.net.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* UDP发送数据的步骤
* A:创建发送端的socket服务对象
* B:创建数据,并将数据打包
* C:通过socket对象的发送功能发送数据包
* D:释放资源
*
*/
public class SendDemo {
public static void main(String[] args) throws IOException {
//A:创建发送端的socket服务对象
DatagramSocket dSocket = new DatagramSocket();
/**
* B:创建数据,并将数据打包
* buf:要发送的数据信息
* length:发送的数据长度
* address:表示要发到哪里去,对于的那个IP地址
* port:端口号
* getBytes()使用平台的默认字符集将此 String 编码为 byte 序列,
* 并将结果存储到一个新的 byte 数组中
*/
byte[] buf = "hello test socket".getBytes();
int length = buf.length;
InetAddress address = InetAddress.getByName("192.168.31.222");
int port = 10010;
DatagramPacket p = new DatagramPacket(buf, length, address, port);
//C:通过socket对象的发送功能发送数据包
dSocket.send(p);
//D:关闭
dSocket.close();
}
}
receiver
端
package com.net.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* UDP协议接收数据步骤
* A:创建接收端的socket对象
* B:创建一个数据包用于接收数据
* C:接收数据
* D:解析数据,并显示在控制台
* E:释放资源
*
*/
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//A:创建接收数据的socket对象,并指定端口号(端口号随意只要与send端一致就行)
DatagramSocket ds = new DatagramSocket(10086);
/**
* B:设置缓冲区
* new String(byte[] buf,int index,int length);
* 通过使用平台默认的字符集解码指定的byte数组
* buf;要解码的数组
* index:要解码的第一个buf的索引
* length:要解码的byte数(并不是buf的长度)
* p.getLength:将要发送或接收到的数据的长度。
*/
byte[] buf = new byte[1024];
int length = buf.length;
DatagramPacket dp = new DatagramPacket(buf, length);
//C接收数据
ds.receive(dp); //阻塞式方式,所以会一直在运行
//D:解析数据
InetAddress address = dp.getAddress();
String ip = address.getHostName();
//返回缓冲区
byte[] byss = dp.getData();
//返回实际长度
int len = dp.getLength();
String s = new String(byss, 0, len);
System.out.println(ip + "--" + s);
//E:释放资源
ds.close();
}
}
如果想要不同的电脑都看到结果的话,就将IP地址改为广播地址X.X.X.255
,就实现了不同电脑都可以看到你发送的消息了,
另外增强版:主要模拟qq发送消息实现,此处增加IO以及线程实现聊天功能
聊天控制端
package com.net.udp4;
import java.io.IOException;
import java.net.DatagramSocket;
/**
* 多线程改进聊天
*/
public class ChatDemo {
public static void main(String[] args) throws IOException {
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receiveSocket = new DatagramSocket(12580);
SendThread sendT = new SendThread(sendSocket);
ReceiveThread receiveT = new ReceiveThread(receiveSocket);
Thread send = new Thread(sendT);
Thread receive = new Thread(receiveT);
send.start();
receive.start();
}
}
增强版send端
package com.net.udp4;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class SendThread implements Runnable {
DatagramSocket sendSocket;
public SendThread(DatagramSocket sendSocket) {
this.sendSocket = sendSocket;
}
@Override
public void run() {
//封装键盘录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
try {
while ((line = br.readLine()) != null) {
if ("88".equals(line)) {
break;
}
byte[] buf = line.getBytes();
//改成广播地址192.168.31.255
DatagramPacket p = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.31.255"), 12580);
sendSocket.send(p);
}
} catch (IOException e) {
e.printStackTrace();
}
sendSocket.close();
}
}
增强版接收端
package com.net.udp4;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveThread implements Runnable {
DatagramSocket receiveSocket;
public ReceiveThread(DatagramSocket receiveSocket) {
this.receiveSocket = receiveSocket;
}
@Override
public void run() {
while (true) {
byte[] buf = new byte[1024];
/**
* buf - 保存传入数据报的缓冲区。
* len - 要读取的字节数。
*/
DatagramPacket p = new DatagramPacket(buf, buf.length);
try {
receiveSocket.receive(p);
} catch (IOException e) {
e.printStackTrace();
}
String ip = p.getAddress().getHostAddress();
String name = p.getAddress().getHostName();
String parse = new String(p.getData(), 0, p.getLength());
System.out.println("ip地址为:" + ip + ";计算机名为:" + name + ";发的消息为 " + parse);
//接收端相当于服务器,所以不能一次执行之后就结束,且不需要关闭
//receiveSocket.close();
}
}
}
大致实现的功能展示(很简陋) 222是我自己,159 是另外一台电脑:
这样,大概的功能就展现出来了,我就可以看到自己发送的消息,以及别人发送的消息了,只是样式很丑啦。。。。哈哈哈哈哈哈。
–end