18 网络编程(UDP,TCP协议编程)
网络编程
概述
概念 :
计算机网络是通过传输介质 , 通信设施和网络通信协议 , 把分散在不同地点的计算机设备不连起来 , 实现资源共享和数据传输的系统 . 网络边喝茶能就是编写程序使联网的两个 ( 或多个 ) 设备 ( 例如计算机 ) 之间进行数据传输 . Java语言对网络编程提供了良好的支持 , 通过其提供的接口我们可以很方便的进行网络编程 .
网络模型
-
OSI
世界上第一个网络体系结构由IBM公司提出 ( 1974年 , SNA ) , 以后其他公司也相继提出自己的网络体系结构 . 如 : DIgital公司的DNA , 美国国防部的 TCP/IP 等 , 多种网络体系结构并存 , 其结果是若采用IBM的结构 , 只能选用IBM的产品 , 只能与同种结构的网络互联
为了促进计算机网络的发展 , 国际标准化组织 ISO于1977年成立了一个委员会 , 在现有网络的基础上 , 提出了不基于具体机型 , 操作系统或公司的网络体系结构 , 称为开放系统互连参考模型 , 即OSI/RM ( Open System Interconnection Reference Model ) . OSI模型把网络通信的工作分为7层 , 分别是物理层 , 数据链路层 , 网络层 , 传输层 , 会话层 , 表示层和应用层 .
-
TCP/IP
OSI参考模型的初衷是提供全世界范围的计算机网络都要遵循的统一标准 , 但是由于存在模型和协议自身的缺陷 , 迟迟没有成熟的产品推出 . TCP/IP协议在实践中不断完善和发展取得成功 , 作为网络的基础 , Internet的语言 , 可以说没有TCP/IP协议就没有互联网的今天 .
TCP/IP , 即Transmission Control Protocol的简写 , 中译名为传输控制协议/因特网互联协议 , 是Internet最基本的协议 , Internet国际互联网络的基础 .
TCP/IP协议是一个开放的网络协议簇 , 它的名字主要取自最重要的网络层IP协议和传输层TCP协议 . TCP/IP协议定义了电子设备如何连入因特网 , 以及数据如何在它们之间传输的标准 . TCP/IP参考模型采用4层的层级结构 , 每一层都呼叫它的下一层所提供的协议来完成自己的需求 , 这4个层次分别是 : 网络接口层 , 互联网层 ( IP层 ) , 传输层 ( IP层 ) , 应用层 .
-
IP地址和MAC地址
IP : 网络地址
MAC : 物理地址 , 网卡地址 , 全球唯一
-
局域网和互联网
局域网 : 只能在本网络内访问
互联网 : 可以和网络上的任意节点进行访问
-
DNS
域名解析服务器
网络三要素
IP地址
-
32位二进制 , 是网络上联通的虚拟地址
-
点名十进制表示法
-
ABC类IP
-
A类地址范围:1.0.0.0到126.255.255.255
- A类地址中的保留地址:127.0.0.0到127.255.255.255是保留地址,用做循环测试用的
127.0.0.1(域名是localhost)是回送地址,指本地机,一般用来测试使用。回送地址是主机IP堆栈内部的IP地址,主要用于网络软件测试以及本地机进程间通信,一旦使用回送地址发送数据,协议软件立即返回,不进行任何网络传输
- A类私有地址:10.0.0.0到10.255.255.255
-
B类地址范围:128.0.0.0到191.255.255.255
- B类地址中的保留地址:169.254.0.0到169.254.255.255是保留地址
- B类私有地址:172.16.0.0到172.31.255.255。
-
C类地址范围:192.0.0.0到223.255.255.255
- C类私有地址:192.168.0.0到192.168.255.255是私有地址
前3个字节网络地址,第4个个字节为主机地址。第1个字节的前三位固定为110
-
-
IPV
- IPv4
- IPv6
-
本地地址 : 127.0.0.1
-
广播地址 : 广播地址应用于网络内的所有主机
-
受限广播
不被路由发送 , 但会被送到相同物理网络段上的所有主机IP地址的网络字段和主机字段全为1就是地址255.255.255.255
-
直接广播
网络广播会被路由 , 并会发送到专门网络上的每台主机IP地址的网络字段定义这个网络 , 主机字段通常为1 , 如192.168.10.255
-
端口号
- 用于区分网络进程
- 0-65535
- 0-1024 : 系统保留
协议
- UDP
- 将数据源和目的封装成数据包中 , 不需要建立连接
- 每个数据包的大小限制在64K
- 因无连接 , 是不可靠协议
- 不需要建立连接 , 速度快
- TCP
- 建立连接 , 形成传输数据的通道
- 在连接中进行大数据量传输
- 通过三次握手完成连接 , 是可靠协议
- 必须建立连接 , 效率会稍低
- TCP一般用于文件传输 ( FTP HTTP对数据准确性要求高 , 速度可以相对慢 , 发送或接收邮件 ( POP IMAP SMTP对数据准确性要求高 , 非紧急应用 ) , 远程登录 ( TELNET SSH对数据准确性有一定要求 , 有连接的概念 ) 等等
- UDP一般用于即时通信 ( QQ聊天对数据准确性和丢包要求比较低 , 但速度必须快 ) , 在线视频 ( RTSP速度一定要快 , 保证视频连续 , 但是偶尔花了一个图像帧 , 人们还是能接受的 ) , 网络语音电话 ( VoIP语音数据包一般比较小 , 需要高速发送 , 偶尔断音或串音也没有问题 ) 等等 .
InetAddress用法
- Java中用于获取IP地址的类 , 里面封装了IP地址 , 主机名等信息
public static InetAddress getByName(String host)
public static InetAddress getLocalHost()
public String getHostAddress()
public String getHostName()
import java.net.InetAddress;
public class SocketDemo2 {
public static void main(String[] args) throws Exception {
InetAddress name = InetAddress.getByName("DESKTOP-Q0I9JB6");
System.out.println(name);
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
String ip = localHost.getHostAddress();
String hname = localHost.getHostName();
System.out.println(ip + "=="+hname);
}
}
UDP协议编程
- UDP : 是一种无状态的传入协议 , 无需建立连接 , 效率快
- UDP协议的客户端和服务端用的都是DatagramSocket类 , 传输的目的地在DatagramPacket数据报包中指定
案例一 :
服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPClient {
public static void main(String[] args) throws Exception {
//创建客户端,用于发送数据
DatagramSocket ds = new DatagramSocket();
//准备数据
String str = "在么?醒了么?吃了么?一起睡觉么?";
DatagramPacket dp = new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("SPIDERMAN"),8888);
//发送数据
ds.send(dp);
//关闭资源
ds.close();
}
}
服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPServer {
public static void main(String[] args) throws Exception {
//创建服务端对象
DatagramSocket ds = new DatagramSocket(8888);
//创建一个空数据包,用来接受数据
DatagramPacket dp = new DatagramPacket(new byte[1024*64], 1024*64);
//接受数据
ds.receive(dp);
//拆数据
byte[] bs = dp.getData();
int len = dp.getLength();
//客户端发送的IP的对象
InetAddress ip = dp.getAddress();
String str = new String(bs,0,len);
System.out.println(ip.getHostAddress()+":"+str);
//关闭资源
//ds.close();
}
}
案例二 :
客户端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class UDPClientDemo {
public static void main(String[] args) throws Exception {
//创建客户端对象
DatagramSocket ds = new DatagramSocket();
Scanner sc = new Scanner(System.in);
System.out.println("请开始骚扰");
//找到服务端的IP地址
InetAddress address = InetAddress.getLocalHost();
while(true) {
String s = sc.next();
DatagramPacket dp = new DatagramPacket(s.getBytes(), s.getBytes().length,address,8800);
ds.send(dp);
if (s.equals("886")) {
break;
}
}
ds.close();
}
}
服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPServerDemo {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket(8800);
while(true) {
DatagramPacket dp = new DatagramPacket(new byte[1024*64], 1024*64);
ds.receive(dp);
int len = dp.getLength();
byte[] by = dp.getData();
String ip = dp.getAddress().getHostAddress();
String s = new String (by,0,len);
System.out.println(ip+":"+s);
if (s.equals("886")) {
break;
}
}
ds.close();
}
}
TCP协议编程
客户端
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws Exception {
Socket s = new Socket("127.0.2.1",9999);
OutputStream os = s.getOutputStream();
os.write("女神一起玩耍嘛".getBytes());
InputStream is = s.getInputStream();
byte[] by = new byte[1024];
int len = is.read(by);
System.out.println("来自女神的回复:"+new String(by,0,len));
os.close();
s.close();
}
}
服务端
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws Exception {
//创建服务器对象
ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept();
InputStream is = s.getInputStream();
byte[] by = new byte[1024];
int len = is.read(by);
System.out.println(new String(by,0,len));
//服务器给客户端回消息
OutputStream os = s.getOutputStream();
os.write("好的哟~".getBytes());
os.close();
is.close();
s.close();
ss.close();
}
}
TCP应用案例
使用缓冲字符流传输数据
- 可以利用缓冲字符流中的newLine和readLine
客户端
/**
* 客户端发送给服务端一句话,使用缓冲字符流实现
*
*/
public class ClientDemo {
public static void main(String[] args) {
try {
Socket s = new Socket("localhost",8888);//0-65535
OutputStream out = s.getOutputStream();
//包装成缓冲字符流
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(out));
BufferedReader br = new BufferedReader(
new InputStreamReader(s.getInputStream()));
bw.write("早上好,在么");
bw.newLine();
bw.flush();
System.out.println(br.readLine());
bw.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端
public class ServerDemo {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
System.out.println("服务端启动.......");
Socket s = ss.accept();
InputStream in = s.getInputStream();
//包装城缓冲字符流
BufferedReader br = new BufferedReader(
new InputStreamReader(in));
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
String str = br.readLine();
System.out.println(str);
bw.write("在呢,你猜我在不在洗澡");
bw.newLine();
bw.flush();
br.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端从键盘录入并发送
客户端
public class ClientDemo2 {
public static void main(String[] args) {
try {
Socket s = new Socket("localhost",8888);
Scanner sc = new Scanner(System.in);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line;
while((line = sc.nextLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
if("over".equals(line)) {
break;
}
}
bw.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端
public class ServerDemo2 {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
Socket s = ss.accept();
InetAddress ip = s.getInetAddress();
System.out.println(ip.getHostAddress()+" connected.....");
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
while((line = br.readLine())!=null) {
System.out.println(line);
}
br.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端键盘录入服务端转大写返回
- 客户端通过键盘录入,得到一个字符串,发送给服务端,服务端打印服务端把该字符换转成大写,再协写回给客户端
客户端
public class ClientDemo3 {
public static void main(String[] args) {
try {
Socket s = new Socket("localhost",8888);
Scanner sc = new Scanner(System.in);
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter
(s.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
while((line = sc.nextLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
if("over".equals(line)) {
break;
}
System.out.println(br.readLine());
}
bw.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端
public class ServerDemo3 {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
Socket s = ss.accept();
InetAddress ip = s.getInetAddress();
System.out.println(ip.getHostAddress()+" connected.....");
BufferedReader br = new BufferedReader(
new InputStreamReader(s.getInputStream()));
BufferedWriter bw = new BufferedWriter
(new OutputStreamWriter(s.getOutputStream()));
String line;
while((line = br.readLine())!=null) {
System.out.println(line);
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
br.close();
s.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端向服务端发送一张图片
- 客户端从本地取得一张图片
- 客户端和服务端建立网络连接 , 获取输出流
- 使用网络上输出流将读取的图片写到服务端
- 服务端读取客户端过来的图片 , 保存到本地
客户端
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.Socket;
public class UpLoadMapClient {
public static void main(String[] args) throws Exception {
Socket s = new Socket("127.0.0.1",4646);
//先将本地图片加载到socket流里面
FileInputStream fis = new FileInputStream("D:\\邢菲.jpg");
OutputStream os = s.getOutputStream();
byte[] by = new byte[1024];
int len = 0;
while ((len = fis.read(by)) != -1) {
os.write(by,0,len);
}
os.close();
fis.close();
s.close();
}
}
服务端
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class UploadMapServer implements Runnable{
@Override
public void run() {
ServerSocket ss = null;
Socket a = null;
InputStream is = null;
FileOutputStream fos = null;
try {
ss = new ServerSocket(4646);
a = ss.accept();
is = a.getInputStream();
fos = new FileOutputStream("F://xf1.jpg");
byte[] by = new byte[1024];
int len = 0;
while ((len = is.read(by)) != -1){
fos.write(by,0,len);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
fos.close();
is.close();
a.close();
ss.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class UpLoadMapTest {
public static void main(String[] args) {
ExecutorService nt = Executors.newFixedThreadPool(3);
nt.execute(new UploadMapServer());
}
}
聊天室
客户端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class ChatRoomClient implements Runnable{
@Override
public void run() {
DatagramSocket ds = null;
try {
//创建客户端对象
ds = new DatagramSocket();
Scanner sc = new Scanner(System.in);
System.out.println("请开始畅所欲言");
InetAddress address = InetAddress.getByName("192.168.0.135");
while (true) {
String s = sc.next();
DatagramPacket dp = new DatagramPacket(s.getBytes(), s.getBytes().length,address,8888);
ds.send(dp);
if (s.equals("886")) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
ds = null;
}
}
}
服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ChatRoomServer implements Runnable{
@Override
public void run() {
//创建服务器对象
DatagramSocket ds = null;
try {
//创建服务器对象
ds = new DatagramSocket(8888);
DatagramPacket dp = new DatagramPacket(new byte[1024*64], 1024*64);
while (true) {
ds.receive(dp);
byte[] by = dp.getData();
String ip = dp.getAddress().getHostAddress();
int len = dp.getLength();
String s = new String(by,0,len);
System.out.println(ip+":"+s);
if (s.equals("886")) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (ds != null) {
ds.close();
}
ds = null;
}
}
}
测试类
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ChatRoomTest {
public static void main(String[] args) throws Exception {
ExecutorService nt = Executors.newFixedThreadPool(3);
nt.execute(new ChatRoomServer());
Thread.sleep(100);
nt.execute(new ChatRoomClient());
}
}