网络编程
1.TCP协议
1.1 TCP协议简介
TCP:Transmission Control Protocol 传输控制协议,是一种面向连接、可靠的、基于字节流传输的传输层通信协议。
TCP的特点:
1、面向连接
2、可靠的传输 安全传输
3、基于字节流
4、传输的大小没有限制
1.2 java中的TCP实现
Socket:套接字 实现通信的端点
用于描述IP和端口号,是一个通信的句柄。网络通信指的就是Socket之间的通信
常用的:
1.构造函数
1.无参构造
`**Socket**()`
2.有参构造:
`**Socket**(InetAddress address, int port)`
2.常用方法
1.获取内容 可以接受其他发来的内容 输入流–>读取
`**getInputStream**()`
2.写出内容 可以向其他发送消息内容 输出流—>写出
`**getOutputStream**()`
3.连接服务器 连接到服务器上
`**connect**(SocketAddress endpoint)`
4.关闭服务器
close()
ServerSocket:服务端套接字 主要用于TCP的服务端
常用的:
1.构造函数 创建实例,指定服务端端口号
ServerSocket(int port)
2.监听客户端的连接 如果没有连接,程序就阻塞在这,等待连接 返回值就是套接字
accept()
3.关闭
close()
1.3 TCP的开发步骤
1.开发服务端
1.创建ServerSocket实例,并指定端口号
2.监听客户端的连接
3.消息交互
4.关闭
1.流
2.套接字
3.服务端套接字
示例代码:
public static void main(String[] args) throws IOException {
//1、创建服务端实例对象,并指定端口号
ServerSocket server=new ServerSocket(8888);
//2、实现客户端连接的监听
Socket client=server.accept();//阻塞监听
System.err.println("客户端连接……");
//3、消息交互 发送消息
client.getOutputStream().write("郑州欢迎你".getBytes());
//4、关闭
client.close();
server.close();
}
2.开发客户端
1.实例化套接字对象,并指定服务端的IP和端口号
2.信息交互
3.关闭、销毁
示例代码:
public static void main(String[] args) throws UnknownHostException, IOException {
//1、实例化套接字对象,并完成服务端的连接
Socket socket=new Socket(InetAddress.getLocalHost(), 8888);
//2、消息交互
//接收消息
InputStream is=socket.getInputStream();
byte[] data=new byte[512];
int length=is.read(data);
System.out.println("客户端:接收服务端的消息:"+new String(data,0,length));
//3、关闭 销毁
is.close();
socket.close();
}
2.4 基于TCP实现一对一聊天
服务端
public class TalkServer {
public static void main(String[] args) throws Exception {
//1、实例化
ServerSocket server=new ServerSocket(10088);
System.out.println("豪杰已在线……等你来撩!");
//2、监听客户端连接
Socket socket=server.accept();
//3、信息交互
//获取对应的输入流和输出流 用户信息的获取和发送
InputStream re=socket.getInputStream();
OutputStream se=socket.getOutputStream();
//发送默认消息
se.write("你好,我是豪杰……".getBytes());
//准备接受消息的数组
byte[] data=new byte[1024];
int len;
//键盘录入
Scanner scanner=new Scanner(System.in);
//循环 聊天
while(true) {
System.out.println("请输入聊天内容:");
String msg=scanner.nextLine();
se.write(msg.getBytes());
len=re.read(data);
System.out.println("豪杰:"+new String(data,0,len));
}
}
}
客户端:
public class TalkClient {
public static void main(String[] args) throws UnknownHostException, IOException {
//1、实例化客户端对象
Socket socket=new Socket(InetAddress.getLocalHost(), 10088);
//2、信息交互
//获取对应的输入流和输出流 用户信息的获取和发送
InputStream re=socket.getInputStream();
OutputStream se=socket.getOutputStream();
//准备接受消息的数组
byte[] data=new byte[1024];
int len;
//键盘录入
Scanner scanner=new Scanner(System.in);
//循环 聊天
while(true) {
len=re.read(data);
System.out.println("老邢:"+new String(data,0,len));
System.out.println("请输入聊天内容:");
String msg=scanner.nextLine();
se.write(msg.getBytes());
}
}
}
V2.0 迭代升级 要求改进一问一答,实现一对一的任意聊天
服务端:
public class TalkServer {
public static void main(String[] args) throws Exception {
//1、实例化
ServerSocket server=new ServerSocket(10088);
System.out.println("***豪杰聊天***");
//2、监听客户端连接
Socket socket=server.accept();
//3、信息交互
//引入线程 实现异步通信 2个线程 一个负责 接受消息、一个负责发送消息
//发送线程
Thread sendThread=new Thread(new Runnable() {
@Override
public void run() {
OutputStream se;
try {
se = socket.getOutputStream();
//发送默认消息
se.write("你好,我是豪杰……".getBytes());
//键盘录入
Scanner scanner=new Scanner(System.in);
while(true) {
System.out.println("请输入聊天内容:");
String msg=scanner.nextLine();
se.write(msg.getBytes());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
sendThread.start();
//接收线程 用于消息的接收
Thread recThread=new Thread(new Runnable() {
@Override
public void run() {
//获取对应的输入流和输出流 用户信息的获取和发送
InputStream re;
try {
re = socket.getInputStream();
//准备接受消息的数组
byte[] data=new byte[1024];
int len;
while (true) {
len=re.read(data);
System.out.println("豪杰:"+new String(data,0,len));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
recThread.start();
}
}
客户端:
public class TalkClient {
public static void main(String[] args) throws UnknownHostException, IOException {
//1、实例化客户端对象
Socket socket=new Socket(InetAddress.getLocalHost(), 10088);
System.out.println("***老邢聊天***");
//2、信息交互
//引入线程 实现任意聊天
//接收线程 用于消息的接收
Thread recThread=new Thread(new Runnable() {
@Override
public void run() {
//获取对应的输入流和输出流 用户信息的获取和发送
InputStream re;
try {
re = socket.getInputStream();
//准备接受消息的数组
byte[] data=new byte[1024];
int len;
while(true) {
len=re.read(data);
System.out.println("老邢:"+new String(data,0,len));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
recThread.start();
//发送线程 实现消息的发送
Thread sendThread=new Thread(new Runnable() {
@Override
public void run() {
OutputStream se;
try {
se = socket.getOutputStream();
//键盘录入
Scanner scanner=new Scanner(System.in);
while(true) {
System.out.println("请输入聊天内容:");
String msg=scanner.nextLine();
se.write(msg.getBytes());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
sendThread.start();
}
}
2. UDP协议
2.1 UDP协议简介
UDP:User Datagram Protocol 用户数据报协议。是一种不可靠,面向无连接的传输层通信协议。
UDP特点:
1.面向无连接
2.不可靠传输
3.每次传输的内容不能超过64KB
4.性能高效
UDP的不可靠传输:udp仅仅在数据报的头部,添加了复用和数据校验。
Ftp协议 底层 udp
Http协议 底层 tcp
2.2 java中的UDP实现
Java支持udp协议,对UDP进行类的封装。
1.DatagramPacket 数据报包
主要是包含要发送或接收的数据。和对应数据的IP地址和端口号
数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。
常用的:
1.构造函数
a.接收数据的数据报包
DatagramPacket(byte[] buf, int length)
b.发送数据的数据报包
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
2.获取内容
getData()
3.设置内容
setData(byte[] buf)
4.获取长度
getLength()
2.DatagramSocket 用来发送和接收数据报包的套接字
可以实现基于UDP协议进行通信,可以发送或者接收 对应的数据报包
常用的:
1.构造函数
DatagramSocket(int port)
2.接收数据报包
receive(DatagramPacket p)
3.发送数据报包
send(DatagramPacket p)
4.关闭
close()
2.3 UDP开发步骤
1.实例化套接字对象
2.实例化 数据报包 接收报包和发送报包
3.发送或接收内容
4.关闭销毁
示例代码:接收消息
public class UdpClient01 {
public static void main(String[] args) throws IOException {
//1、实例化套接字对象
DatagramSocket socket=new DatagramSocket(8881);
//2、实例化数据报包 用于消息的接收
byte[] arr=new byte[1024];
DatagramPacket rPacket=new DatagramPacket(arr, arr.length);
//3、接收消息
socket.receive(rPacket);
//4、显示信息
System.out.println("接收消息:"+new String(rPacket.getData(),0,rPacket.getLength()));
//5、关闭
socket.close();
}
}
发送消息:
public class UdpClient02 {
public static void main(String[] args) throws IOException {
//1、实例化套接字对象
DatagramSocket socket=new DatagramSocket(8882);
//2、实例化 发送数据的数据报包
byte[] arr="内涵段子".getBytes();
DatagramPacket sPacket=new DatagramPacket(arr, arr.length,InetAddress.getLocalHost(),8881);
//3、发送消息
socket.send(sPacket);
//4、关闭
socket.close();
}
}
2.4 基于UDP实现聊天室
需求:使用udp协议实现网络聊天室
示例代码:聊天室,转发器
public class TalkRoom {
public static void main(String[] args) throws Exception{
//1、创建套接字
DatagramSocket socket=new DatagramSocket(10010);
//2、准备集合 记录 在线的地址信息 记录端口号
HashSet<Integer> ads=new HashSet<>();
//3、准备发送和接收的字节数组
byte[] sarr=new byte[1024];
byte[] rarr=new byte[1024];
//4、实例化 数据报包
DatagramPacket sdata=new DatagramPacket(sarr, sarr.length);
DatagramPacket rdata=new DatagramPacket(rarr, rarr.length);
String msg;
System.out.println("*******聊天室*******");
//5、循环 接收和转发消息
while(true) {
//接收消息
socket.receive(rdata);
//获取接收到的消息
//校验当前客户端是否已经记录
if(!ads.contains(rdata.getPort())) {
ads.add(rdata.getPort());
}
//获取接收的消息
msg=new String(rarr,0,rdata.getLength());
System.err.println("聊天室:"+msg);
//转发消息 其他人 不包含发消息的人
for(Integer port:ads) {
if(port!=rdata.getPort()) {
sdata.setAddress(InetAddress.getLocalHost());
sdata.setPort(port);
sdata.setData(msg.getBytes());
socket.send(sdata);
}
}
}
}
}
聊天室客户端:
public class TalkClient01 {
public static void main(String[] args) throws SocketException {
//1、实例化套接字
DatagramSocket socket=new DatagramSocket(9001);
//2、线程池 多线程进行聊天 1个线程负责发送消息 1个负责接收消息
ThreadPoolExecutor tpe=new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
//3、发送线程
tpe.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//1.数据报包
byte[] arr=new byte[1024];
DatagramPacket sdata;
try {
sdata = new DatagramPacket(arr, arr.length,InetAddress.getLocalHost(),10010);
String m;
Scanner scanner=new Scanner(System.in);
while(true) {
System.out.println("我说 :");
m=scanner.nextLine();
//设置发送消息
sdata.setData(m.getBytes("UTF-8"));
//发送消息
socket.send(sdata);
}
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
//4、接收线程
tpe.execute(new Runnable() {
@Override
public void run() {
//1.实例化数据报包
byte[] arr=new byte[1024];
DatagramPacket rdata=new DatagramPacket(arr, arr.length);
while(true) {
try {
//接收消息
socket.receive(rdata);
System.out.println("别人说:"+new String(arr,0,rdata.getLength()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
}
示例代码:聊天室客户端02
public class TalkClient02 {
public static void main(String[] args) throws SocketException {
//1、实例化套接字
DatagramSocket socket=new DatagramSocket(9002);
//2、线程池 多线程进行聊天 1个线程负责发送消息 1个负责接收消息
ThreadPoolExecutor tpe=new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
//3、发送线程
tpe.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//1.数据报包
byte[] arr=new byte[1024];
DatagramPacket sdata;
try {
sdata = new DatagramPacket(arr, arr.length,InetAddress.getLocalHost(),10010);
String m;
Scanner scanner=new Scanner(System.in);
while(true) {
System.out.println("我说 :");
m=scanner.nextLine();
//设置发送消息
sdata.setData(m.getBytes("UTF-8"));
//发送消息
socket.send(sdata);
}
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
//4、接收线程
tpe.execute(new Runnable() {
@Override
public void run() {
//1.实例化数据报包
byte[] arr=new byte[1024];
DatagramPacket rdata=new DatagramPacket(arr, arr.length);
while(true) {
try {
//接收消息
socket.receive(rdata);
System.out.println("别人说:"+new String(arr,0,rdata.getLength()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
}