网络编程
网络编程主要用于解决计算机与计算机的数据通信问题。
网络通信三要素:
1、ip
2、通信协议
3、端口号:用于表明是给哪一个应用程序来处理。
IP
IP地址:IP地址的本质就是由一个32位的二进制数据组成的。后来为了方便记忆IP地址,就把ip地址切成了4份。每份为8位,每段可以表示2^8(256)个数字,(0-255)
00000000-00000000-00000000-00000000
IP地址的分类
IP地址= 网络号 + 主机号
A类地址 =一个网络号+三个主机号 2^24 政府单位
B类地址= 两个网络号+两个主机号 2^16 事业单位
C类地址=三个网络号+一个主机号 2^8 私人使用
我们使用的网络是由运营商注册的一个C类地址,然后在通过路由器分发下来许多ip。
子网掩码的作用就是标识网络号和主机号的位置。 子网掩码中的255对应的就是网络号。
如果IP地址为 192.168.15.31 ,子网掩码为 255.255.255.0 。
那么网络号就为192.168.31 。主机号为31
InetAddress(IP对象)
InetAddress.getLocalHost()获取本机的IP地址(获取自己的IP地址对象)
InetAddress.getByName(String str) 根据主机名或IP 获取ip地址对象(获取别人的IP地址对象)
InetAddress.getAllByName(“www.baidu.com”) 根据域名获取ip地址【一个域名可能对应多个ip】
ip.getHostName( ) 获取主机名
端口号
端口号范围: 0-65535
0-1023 为公认端口,和系统一些服务进行绑定。
1024–65535 这一范围的端口号,我们可以使用。
通讯协议
网络通信的协议主要有两种协议:
1.UDP通信协议
面向无连接,传输速度快【 面向无连接:把数据封装成数据包直接发送,不需要建立连接(比如对讲机,不管有没有人,都会把消息发送出去)】
每个数据包大小在64K内
因为面向无连接,所以不可靠,容易出现数据丢失问题
udp通信协议不区分客服端与服务端,只区分发送端与接收端
比如:对讲机、飞Q、游戏(如果是面向连接,服务器会等到你连上,才开始游戏,肯定是影响效率,所以游戏基本上是面向无连接的。)
UDP通信协议中有一个IP地址被称作广播地址,广播地址为主机号为255的地址。 如果你的IP为192.168.1.1 。子网掩码为255.255.0.0 ,那么广播地址就是192.168.255.255 【TCP中没有广播地址】
2.TCP通信协议
面向连接【通过三次握手机制连接,可靠性协议,但是传输速度慢。】
大小不限制
网络通信
在java中网络通信被称为Socket通信,要求通信的两台机器必须要安装Socket。
不同的通信协议就会有不同的Socket。
UDP
UDP通信协议下的Socket:
DatagrameSocket udp插座服务
DatagramPacket 数据包类
UDP面向无连接,传输过程都会通过数据包进行通信。UDP通信很想码头运输箱的传送过程。运输箱上记载运输的地址。不区分客户端与服务端,只区分发送端与接收端
UDP通信Demo
发送端:
public static void main(String[] args) throws IOException {
//建立UDP服务
DatagramSocket datagramSocket=new DatagramSocket();
//建立数据包
String str="大家好";
byte[]buf=str.getBytes();
DatagramPacket packet=new DatagramPacket(buf, buf.length, InetAddress.getLocalHost(), 8080);
//发送
datagramSocket.send(packet);
//释放资源--实际上释放占用的端口号
datagramSocket.close();
}
接收端:
public static void main(String[] args) throws IOException {
//建立UDP服务,
DatagramSocket datagramSocket=new DatagramSocket(8080);
while(true) {
//建立数据包
byte[]buf=new byte[1024];
DatagramPacket packet=new DatagramPacket(buf, buf.length);
//接受数据存储到数据包
datagramSocket.receive(packet);
System.out.println(new String(packet.getData()));
}
}
自定义UDP发送端与飞秋进行通信
1.飞Q监听2425接口,使用UDP通信协议,此时可以写一个发送端,发送消息给本地2425端口。
public static void main(String[] args) throws IOException {
//建立UDP服务
DatagramSocket datagramSocket=new DatagramSocket();
//建立数据包
String str="大家好";
byte[]buf=str.getBytes("gbk");
DatagramPacket packet=new DatagramPacket(buf, buf.length, InetAddress.getLocalHost(), 2425);
//发送
datagramSocket.send(packet);
//释放资源--实际上释放占用的端口号
datagramSocket.close();
}
2.发送消息,在飞Q中没有接受到。
原因:每个网络程序都有自己所处理的特定格式,如果接受的数据不符合指定的格式,那么就会被当成垃圾数据丢弃。(相当于数据加密)
飞Q接收的数据格式:
version:time:sender:ip:flag:content
版本号 时间 发送人 IP 发送的标志符号(32) 真正的内容
将上述代码改编如下:
public static void main(String[] args) throws IOException {
//建立UDP服务
DatagramSocket datagramSocket=new DatagramSocket();
//建立数据包
String str="大家好";
byte[]buf=str.getBytes("gbk");
DatagramPacket packet=new DatagramPacket(buf, buf.length, InetAddress.getLocalHost(), 2425);
//发送
datagramSocket.send(packet);
//释放资源--实际上释放占用的端口号
datagramSocket.close();
}
public static String getData(String str) {
StringBuffer sb=new StringBuffer();
sb.append("1.0:");
sb.append(System.currentTimeMillis()+":");
sb.append("xiao:");
sb.append("192.168.1.1:");
sb.append("32:");
sb.append(str);
return sb.toString();
}
```c
在这里插入代码片
实现效果:
udp广播
在UDP通信协议中有一个IP被称为广播IP。 广播IP就是主机号为255的IP。
本地IP : 192.168.0.1
子网掩码:255.255.255.0 ===》》 广播地址:192.168.0.255
本地IP : 192.168.0.1
子网掩码:255.255.0.0 ===》》 广播地址:192.168.255.255
例子:
public static void main(String[] args) throws IOException {
//建立UDP服务
DatagramSocket datagramSocket=new DatagramSocket();
//建立数据包
String str=getData("大家好");
byte[]buf=str.getBytes("gbk");
//广播
//本机IP 192.168.0.4
//子网掩码 255.255.255.0
//广播地址 192.168.0.255
DatagramPacket packet=new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.0.255"), 2425);
//发送
datagramSocket.send(packet);
//释放资源--实际上释放占用的端口号
datagramSocket.close();
}
public static String getData(String str) {
StringBuffer sb=new StringBuffer();
sb.append("1.0:");
sb.append(System.currentTimeMillis()+":");
sb.append("xiao:");
sb.append("192.168.1.1:");
sb.append("32:");
sb.append(str);
return sb.toString();
}
模拟群聊
public class App {
public static void main(String[] args) {
Sender sender=new Sender();
sender.start();
Receiver receiver=new Receiver();
receiver.start();
}
}
/**
* 发送
* @author Administrator
*
*/
class Sender extends Thread{
@Override
public void run() {
try {
DatagramSocket sender=new DatagramSocket();
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
while(true) {
String msg = reader.readLine();
byte[]buf=msg.getBytes();
DatagramPacket packet=new DatagramPacket(buf, buf.length,InetAddress.getByName("192.168.0.255"),8080);
sender.send(packet);
}
} catch (Exception e) {
}
}
}
/**
* 接受
* @author Administrator
*
*/
class Receiver extends Thread {
@Override
public void run() {
try {
DatagramSocket datagramSocket=new DatagramSocket(8080);
byte[]buf=new byte[1024];
DatagramPacket packet=new DatagramPacket(buf, buf.length);
while(true) {
datagramSocket.receive(packet);
System.out.println(packet.getAddress().getHostAddress()+":"+new String(packet.getData()));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
使用JFrame写一个飞Q
。。。。。。。。。。。。
。。。。。。。。。。。。。
//TODO
//TODO
//TODO
//TODO
TCP
TCP的引入
UDP是一个不可靠的通信协议,数据包可能会丢失。
什么情况下数据会丢失?
1.带宽不足
2.CPU的处理能力不足
在传输exe文件或电影时如果使用udp通信协议,加入丢失一点数据,就会导致整个文件不能使用。所以这时候引入了TCP通信协议。
UDP通信协议特点:
1.面向无连接,传输速度快。
2.UDP是基于数据包进行传输,每个数据包大小限制在64K内
3.因为无连接,所以不可靠。
4.因为不用建立连接,所以速度快。
5.UDP不区分客户端与服务端,只区分发送端与接收端
TCP通信协议的特点:
1.面向连接,传输速度慢,
2.TCP是基于IO流进行数据传输。数据的大小不受限制
3.TCP面向连接,通过三次握手的机制保证数据的完整性(你在么、我在。我收到了。)。可靠协议
4.tcp是面向连接的,所以速度慢。
5.tcp是区分客户端与服务端的
三次握手机制
发送数据前,检测数据通路书否
为什么ServerSocket不设计一个getInputStream()/getOutPutStream()方法
假如同时有两个用户给服务端发送信息,ServerSocket获取一个输入流,读取信息时,会同时读取到两个信息。 服务器肯定是紊乱。 所以JDK设计了一个Socket类。凡是和服务端建立连接,都会产生一个Socket。
代码示例
1.使用客户端和服务端实现一问一答。在eclispe中运行客户端。 在cmd中运行服务端。【使用java命令运行字节码文件 java 类的全路径】
客户端
public class Client {
@SuppressWarnings("resource")
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket=new Socket(InetAddress.getLocalHost(),8080);
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream(),"gbk"));
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"gbk"));
BufferedReader ins=new BufferedReader(new InputStreamReader(System.in));
String content=null;
while((content=ins.readLine())!=null) {
writer.write(content+"\r\n");
writer.flush();
System.out.println("收到服务端信息:"+reader.readLine());
}
}
}
服务端
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(8080);
//连接
Socket socket = serverSocket.accept();
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream(),"gbk"));
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"gbk"));
BufferedReader ins=new BufferedReader(new InputStreamReader(System.in));
String content=null;
while((content=reader.readLine())!=null) {
System.out.println("收到客户端信息:"+content+"\r\n");
writer.write(ins.readLine()+"\r\n");
writer.flush();
}
}
}
模拟Tomcat
简化版
浏览器本身就是采用了TCP通信原理。
public class TomcatDemo {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(80);
Socket socket = serverSocket.accept();
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("<h1>Hello World</h1>");
writer.flush();
}
}
加强版【多线程】
public class TomcatDemo extends Thread {
private Socket socket;
public TomcatDemo(Socket socket) {
this.socket=socket;
}
@Override
public void run() {
try {
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("<h1>Hello World</h1>");
writer.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(80);
while(true) {
Socket socket = serverSocket.accept();
new TomcatDemo(socket).start();
}
}
}
加强版【传输图片】
public class TomcatDemo extends Thread {
private Socket socket;
public TomcatDemo(Socket socket) {
this.socket=socket;
}
@Override
public void run() {
try {
FileInputStream in=new FileInputStream(new File("d:/a.jpg"));
OutputStream out = socket.getOutputStream();
int content=-1;
while((content=in.read())!=-1) {
out.write(content);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(80);
while(true) {
Socket socket = serverSocket.accept();
new TomcatDemo(socket).start();
}
}
}
80是一个特殊的端口,浏览器访问时可以不用写