网络编程三要素: IP,端口号,协议
1.IP
- ipconfig:查看本机IP192.168.12.42
- ping:测试连接192.168.40.62
- 本地回路地址:127.0.0.1 255.255.255.255是广播地址
- IPv4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。
- IPv6:8组,每组4个16进制数。
- 1a2b:0000:aaaa:0000:0000:0000:aabb:1f2f
- 1a2b::aaaa:0000:0000:0000:aabb:1f2f
- 1a2b:0000:aaaa::aabb:1f2f
- 1a2b:0000:aaaa::0000:aabb:1f2f
- 1a2b:0000:aaaa:0000::aabb:1f2f
2. 端口号
- 每个程序在设备上的唯一标识
- 每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。
- 端口号范围从0-65535
- 编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
- 常用端口
- mysql: 3306
- oracle: 1521
- web: 80
- tomcat: 8080
- QQ: 4000
- feiQ: 2425
3.协议
- 为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
- UDP用户数据报协议
面向无连接,数据不安全,速度快。不区分客户端与服务端。 - TCP传输控制协议
面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。- 三次握手: 客户端先向服务端发起请求, 服务端响应请求, 传输数据
Socket
Socket套接字概述:
- 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
- 通信的两端都有Socket。
- 网络通信其实就是Socket间的通信。
- 数据在两个Socket间通过IO流传输。
- Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port。
网络编程(TCP协议)
- 1.客户端
- 创建
Socket
连接服务端(指定ip地址,端口号),通过ip地址找对应的服务器 - 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
- 输入流可以读取服务端输出流写出的数据
- 输出流可以写出数据到服务端的输入流
- 创建
Socket socket = new Socket("127.0.0.1", 3000);
InputStream is = socket.getInputStream(); //获取客户端输入流
OutputStream os = socket.getOutputStream(); //获取客户端的输出流
byte[] arr = new byte[1024];
int len = is.read(arr); //读取服务器发过来的数据
System.out.println(new String(arr,0,len)); //将数据转换成字符串并打印
os.write("java如何学习?".getBytes()); //客户端向服务器写数据
socket.close();
- 2.服务端
- 创建
ServerSocket
(需要指定端口号) - 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
- 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
- 输入流可以读取客户端输出流写出的数据
- 输出流可以写出数据到客户端的输入流
- 创建
ServerSocket server = new ServerSocket(3000);
Socket socket = server.accept(); //接收客户端的请求
InputStream is = socket.getInputStream(); //获取客户端输入流
OutputStream os = socket.getOutputStream(); //获取客户端的输出流
os.write("百度一下你就知道".getBytes()); //服务器向客户端写出数据
byte[] arr = new byte[1024];
int len = is.read(arr); //读取客户端发过来的数据
System.out.println(new String(arr,0,len)); //将数据转换成字符串并打印
socket.close();
改进–字节流转成字符流
将字节流包装成字符流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
客户端:
Socket socket = new Socket("127.0.0.1", 3000);
BufferedReader br =
new BufferedReader(new InputStreamReader(socket.getInputStream())); //将字节流包装成了字符流
//PrintStream中有写出换行的方法
PrintStream ps = new PrintStream(socket.getOutputStream());
System.out.println(br.readLine());
ps.println("你好,我想买酱油");
System.out.println(br.readLine());
ps.println("海天");
socket.close();
服务器端:
ServerSocket server = new ServerSocket(3000);
Socket socket = server.accept(); //接受客户端的请求
BufferedReader br =
new BufferedReader(new InputStreamReader(socket.getInputStream())); //将字节流包装成了字符流
PrintStream ps = new PrintStream(socket.getOutputStream()); //PrintStream中有写出换行的方法
ps.println("欢迎光临~~");
System.out.println(br.readLine());
ps.println("有喜欢的牌子吗?");
System.out.println(br.readLine());
socket.close();
改进–服务端是多线程的
不断接受客户端请求, 接受一个请求,开启一个线程
//创建服务器
ServerSocket server = new ServerSocket(3000);
while(true) {
//接受客户端的请求
final Socket socket = server.accept();
new Thread() { //匿名内部类方式
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("欢迎光临");
System.out.println(br.readLine());
ps.println("谢谢惠顾");
System.out.println(br.readLine());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}