本帖最后由 小石姐姐 于 2018-4-27 11:35 编辑
黑马七期day12笔记
网络编程
java php ui 前端与移动开发 c/c++ 网络营销 云计算 python
\
Socket (套接字)
用于描述IP地址和端口,是一个通信链的句柄.
Socket就是为网络编程提供的一种机制,通信的两端都有Socket;网络通信其实就是Socket间的通信;数据在两个Socket间通过IO传输.
网络通信三要素(协议 IP地址 端口号)
IP地址:InetAddress(点分十进制表示法)和(网络地址和主机地址)
IPv4和IPv6
公共地址和私有地址(局域网地址)
--网络中设备的表示,不易记忆,可用主机名
端口号
--用于标识进程的逻辑地址,不同进程的标识
传输协议
--通讯的规则\
--常见协议:TCP,UDP
UDP和TCP区别
UDP: USER DATAGRAM PROTOCOL, 用户数据报协议.
特点:
无连接的不可靠协议
数据传输大小限制为64K(一个包)
不需要建立连接即可传输
数据发送速度快, 发送方只发送数据, 不检查接收方是否真正接收到数据, 所以数据可能有丢包的情况
适用场景
适合实时性要求强的场合, 比如网络电话等环境, 这种协议延迟很小
端口号: 就是进程的地址
物理端口 网卡口
逻辑端口 我们指的就是逻辑端口
UDP协议
将数据源和目的封装成数据包中,不需要建立连接;
每个数据报的大小在限制在64K;因无连接,是不可靠协议;不需要建立连接,速度快
TCP协议(有一个管道,要进行连接)
建立连接,行小恒传输数据的通道;在连接中进行大数据量传输;通过三次握手完成
连接,是可靠协议;必须建立连接,效率会稍低
例如:A与B进行三次握手
InetAddress类: 此类表示互联网协议(IP)地址.
使用UDP协议发送数据 (DatagramSocket类:此类表示用来 发送 和 接收 数据,基于UDP协议的)
创建Socket对象
DatagramSocket ds=new DatagramSocket() ;
创建数据并打包
DatagramPacket:此类表示数据报包
数据byte[]
设备的地址IP
进程的地址端口号
发送数据
释放资源
DatagramSocket():创建Socket对象并随机分配端口号
DatagramSocket(int port):创建Socket对象并指定端口号
使用UDP 协议接收数据
-创建接收端Socket对象
//DatagramSocket();创建Socket对象并随即分配端口号
//DatagramSocket(int port):创建Socket对象并指定端口
DatagramSocket ds=new DatagramSocket() ;
-接收数据
-解析数据
-输出数据
-释放资源
java.net.Socket类: 基于TCP协议的Socket, 作为客户端
构造方法
Socket(InetAddress add, int port): 创建TCP客户端对象
成员方法
OutputStream getOutputStream(): 获取输出流对象, 用于发送数据
InputStream getInputStream(): 获取输入流, 用于接收数据
void close(): 释放资源
TCP发送数据步骤
// 1. 创建客户端Socket对象(建立连接)
Socket socket = new Socket(InetAddress地址, 端口号);
// 2. 获取输出流对象
OutputStream outputStream = socket.getOutputStream();
// 3. 发送数据
outputStream.write(byte数组);
// 4. 释放资源
socket.close();
java.net.ServerSocket: TCP服务端
构造方法
ServerSocket(int port): 创建一个TCP服务端, 并监听指定端口
成员方法
Socket accept(): 监听数据, 会阻塞. 收到数据后返回Socket对象
void close(): 关闭Socket
TCP接收数据步骤
// 1. 创建服务端ServerSocket对象:
ServerSocket serverSocket = new ServerSocket(端口号); // 指定要监听的端口号
// 2. 监听数据
Socket socket = serverSocket.accept(); // 该方法会阻塞, 直到有客户端连接
// 3. 获取输入流对象
InputStream inputStream = socket.getInputStream();
// 4. 获取数据
int dataLength = inputStream.read(装数据的byte[]数组);
String s = new String(byte[], 0, dataLength);
// 5. 输出数据
System.out.println(s);
// 6. 释放资源:
socket.close();
serverSocket.close();
TCP协议案例: 客户端发送, 服务端处理后返回客户端
public class TCPClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 10010);
// 获取输出流对象
OutputStream out = socket.getOutputStream();
// 写出数据
out.write("tcp, im coming!".getBytes());
// 接收服务端返回的数据
InputStream in = socket.getInputStream();
// 一次读取一个字节数组
byte[] bys = new byte[1024];
int len;
len = in.read(bys);
// 转换为字符串
String s = new String(bys, 0, len);
System.out.println("客户端接收到服务端响应:"+s);
// 释放资源
socket.close();
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
// 创建服务端ServerSocket
ServerSocket serverSocket = new ServerSocket(10010);
// 监听连接
System.out.println("服务端启动...");
Socket socket = serverSocket.accept();
// 获取输入流对象
InputStream in = socket.getInputStream();
// 读取数据, 一次一个字节数组
byte[] bys = new byte[1024];
int len;
len = in.read(bys);
// 转为字符串
String s = new String(bys, 0, len);
System.out.println("服务端接收到数据:" + s);
// 将字符串转为大写
s = s.toUpperCase();
// 获取输出流, 写回客户端
OutputStream out = socket.getOutputStream();
out.write(s.getBytes());
// 释放资源
socket.close();
}
}
用户登录客户端
*/
public class LoginClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket
Socket socket = new Socket("lishaoqing", 8888);
// 获取键盘录入的用户名和密码
BufferedReader inputBr = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入用户名:");
String username = inputBr.readLine();
System.out.println("请输入密码:");
String password = inputBr.readLine();
// 写出数据
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true); // 自动刷新出去
pw.println(username);
pw.println(password);
// 接收服务端返回的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 读取一行响应结果
String result = br.readLine();
System.out.println(result);
// 释放资源
socket.close();
}
}
模拟用户登录
/*
用户登录服务端
*/
public class LoginServer {
public static void main(String[] args) throws IOException {
// 创建服务端Socket
ServerSocket serverSocket = new ServerSocket(8888);
// 等待连接
System.out.println("服务端启动...");
Socket socket = serverSocket.accept();
// 读取客户端发来的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String username = br.readLine();
String password = br.readLine();
// 判断用户名和密码
boolean canLogin = false;
if ("itheima".equals(username) && "123".equals(password)) {
canLogin = true;
}
// 返回响应结果
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
if (canLogin) {
pw.println("登录成功");
} else {
pw.println("登录失败");
}
// 释放资源
socket.close();
}
}
模拟用户登录案例改写
需求
改进用户信息的存储方式: 上例中只能存储一对用户名和密码. 但现实中会存储很多用户名和密码, 如何存储?
将用户名和密码封装进用户对象, 将多个对象封装到集合中. 用集合来模拟数据库(DB, database)
客户端不改
服务端在接收到客户端发送的用户名和密码后, 将用户名和密码封装到用户对象中, 然后获取集合, 判断该集合中是否有该用户对象(根据用户对象的属性判断), 如果有则登录成功, 没有则登录失败
public class User {
private String username;
private String password;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}
}
/*
模拟用户数据库
*/
public class UserDB {
private static List<User> list = new ArrayList<>();
static {
list.add(new User("zhangsan", "123"));
list.add(new User("lisi", "123"));
list.add(new User("wangwu", "123"));
list.add(new User("zhaoliu", "123"));
}
public static List<User> getUserList() {
return list;
}
}
/*
用户登录服务端
*/
public class LoginServer {
public static void main(String[] args) throws IOException {
// 创建服务端Socket
ServerSocket serverSocket = new ServerSocket(8888);
// 等待连接
System.out.println("服务端启动...");
Socket socket = serverSocket.accept();
// 读取客户端发来的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String username = br.readLine();
String password = br.readLine();
// 判断用户名和密码
boolean canLogin = false;
// 将用户名和密码封装为用户对象
User user = new User(username, password);
if (UserDB.getUserList().contains(user)) {
canLogin = true;
}
// 返回响应结果
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
if (canLogin) {
pw.println("登录成功");
} else {
pw.println("登录失败");
}
// 释放资源
socket.close();
}
}
/*
用户登录客户端
*/
public class LoginClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket
Socket socket = new Socket("lishaoqing", 8888);
// 获取键盘录入的用户名和密码
BufferedReader inputBr = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入用户名:");
String username = inputBr.readLine();
System.out.println("请输入密码:");
String password = inputBr.readLine();
// 写出数据
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true); // 自动刷新出去
pw.println(username);
pw.println(password);
// 接收服务端返回的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 读取一行响应结果
String result = br.readLine();
System.out.println(result);
// 释放资源
socket.close();
}
}
|
|