Java网络编程
1.网络编程相关类的使用:
1.1 InetAddress类
Java提供了InetAddress类来代表ip地址,是对ip地址的抽取和封装,
有两个子类:Inet4Address,Inet6Address,分别表示IPv4和IPv6
public class Demo01 {
public static void main(String[] args) throws UnknownHostException {
//创建IP地址对象
//获取本地IP地址
System.out.println("-------本地IP--------");
InetAddress ia1 = InetAddress.getByName("xxxx.xxxx.xxxx.xxxx"); //本机IP
InetAddress ia2 = InetAddress.getByName("localhost");
InetAddress ia3 = InetAddress.getByName("127.0.0.1");
InetAddress ia4 = InetAddress.getLocalHost();
InetAddress ia5 = InetAddress.getByName("LAPTOP-xxxxxxx");//主机名称
System.out.println("主机地址:"+ia1.getHostAddress()+"主机名:"+ia1.getHostName());
System.out.println("主机地址:"+ia2.getHostAddress()+"主机名:"+ia2.getHostName());
System.out.println("主机地址:"+ia3.getHostAddress()+"主机名:"+ia3.getHostName());
System.out.println("主机地址:"+ia4.getHostAddress()+"主机名:"+ia4.getHostName());
System.out.println("主机地址:"+ia5.getHostAddress()+"主机名:"+ia5.getHostName());
//获取局域网ip
System.out.println("-------局域网ip-------");
InetAddress ia6 = InetAddress.getByName("xxxx.xxxx.xxxx.xxxx");
System.out.println("主机地址:"+ia6.getHostAddress()+"主机名:"+ia6.getHostName());
//获取internet
System.out.println("--------internet---------");
InetAddress ia7 = InetAddress.getByName("www.csdn.com");
System.out.println("主机地址:"+ia7.getHostAddress()+"主机名:"+ia7.getHostName());
InetAddress[] allByName = InetAddress.getAllByName("www.csdn.com");
for (InetAddress inetAddress : allByName) {
System.out.println(inetAddress.getHostAddress());
}
}
}
1.2 URLEncoder类和URLDecoder类
URLEncoder类和URLDecoder类用于完成普通字符串和application/x-www-form-urlencoded MIME字符串之间的转换
public class Demo02 {
public static void main(String[] args) {
String say = "好久不见";
//注意:编码和解码需要采用相同的字符集
try {
//URL编码 URLEncoder:编码,将普通字符串转换为特殊字符串
String encode = URLEncoder.encode(say,"utf-8" );
System.out.println(encode);
//URL解码 URLDecoder:解码,将特殊中文字符串转换为普通字符串
String say2 = URLDecoder.decode(encode, "utf-8");
System.out.println(say2);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
2.基于TCP的网络编程
TCP客户端编码步骤:
1.创建客户端套接字,并指定服务器的地址和端口号
2.获取输入|输出流
3.发送数据
4.关闭
TCP服务器端编码步骤:
1.创建ServerSocket(服务器套接字对象)
2.侦听或监听,返回Socket(客户端套接字),阻塞方法
3.获取输入|输出流
4.处理数据
5.关闭资源
2.1 客户端发送消息,服务端接收消息
/**
* TCP服务器端
*/
public class TCPServer {
public static void main(String[] args) throws Exception{
//创建ServerSocket(服务器套接字对象)
ServerSocket listener = new ServerSocket(10086);
//侦听或监听,返回Socket(客户端套接字),阻塞方法
System.out.println("服务器已启动");
Socket socket = listener.accept();
//获取输入或输出流
InputStream is = socket.getInputStream();
//处理数据
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String data = br.readLine();
System.out.println("客户端说:"+data);
//关闭资源
br.close();
socket.close();
listener.close();
}
}
/**
* TCP客户端
*/
public class TCPClient {
public static void main(String[] args) throws Exception {
//创建客户端套接字Socket,并指定服务器的ip和端口号
Socket socket = new Socket("xxxx.xxxx.xxxx.xxxx", 10086);
//获取输入,输出流
OutputStream os = socket.getOutputStream();
//发送数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
bw.write("好久不见");
//关闭
bw.close();
socket.close();
}
}
2.2 客户端发送消息,服务端回复消息
/**
* TCP服务器端
*/
public class TCPServer {
public static void main(String[] args) throws Exception{
ServerSocket listener = new ServerSocket(10010);
System.out.println("服务器启动了");
Socket socket = listener.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String data = br.readLine();//读取到换行符,返回结果
System.out.println("客户端说"+data);
bw.write("你走开");
bw.newLine();
bw.close();
br.close();
socket.close();
listener.close();
}
}
/**
* TCP客户端
*/
public class TCPClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("xxxx.xxxx.xxxx.xxxx",10010 );
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("好久不见");
bw.newLine();//换行符
bw.flush();//刷新缓冲
String reply = br.readLine();
System.out.println("服务器回复"+reply);
bw.close();
br.close();
socket.close();
}
2.3 客户端上传文件到服务端【以图片为例】
/**
* TCP服务器端
*/
public class FileServer {
public static void main(String[] args) throws Exception{
//创建ServerSocket 并指定端口号
ServerSocket listener = new ServerSocket(8888);
//侦听,返回客户端套接字
System.out.println("服务器已启动");
Socket socket = listener.accept();
//获取输入流
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("图片路径");
byte[] bytes = new byte[1024];
int len = -1;
//读取数据
while ((len = is.read(bytes))!= -1) {
fos.write(bytes,0 ,len );
}
//关闭
fos.close();
is.close();
socket.close();
listener.close();
System.out.println("接收文件完毕");
}
}
/**
* TCP客户端
*/
public class FileClient {
public static void main(String[] args) throws Exception{
//创建socket
Socket socket = new Socket("xxxx.xxxx.xxxx.xxxx",8888 );
//获取输出流
OutputStream os = socket.getOutputStream();
//读取文件并输出
FileInputStream fis = new FileInputStream("图片路径");
byte[] bytes = new byte[1024];
int len = -1;
while ((len = fis.read(bytes))!=-1) {
os.write(bytes,0,len);
}
//关闭
fis.close();
os.close();
socket.close();
System.out.println("发送完毕");
}
}
2.4 多个客户端和一个服务端通信【线程版本】
/**
* 多线程处理
*/
public class ChatThread extends Thread {
private Socket socket;
public ChatThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
if (socket != null) {
try {
InputStream is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
while (true) {
String data = br.readLine();
System.out.println(socket.getInetAddress().getHostAddress() + "说:" + data);
if (data.equals("拜拜") || data.equals("over") || data.equals("886")) {
System.out.println(socket.getInetAddress().getHostAddress() + "退出了");
break;
}
}
} catch (IOException e) {
// e.printStackTrace();
System.out.println(socket.getInetAddress().getHostAddress() + "异常退出了...");
} finally {
try {
br.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* TCP服务器端
*/
public class ChatServer {
public static void main(String[] args) throws Exception{
//1创建ServerSocket
ServerSocket listener=new ServerSocket(9999);
//2监听
System.out.println("聊天服务器已启动....");
try {
while(true) {
Socket socket = listener.accept();
new ChatThread(socket).start();
}
} catch (IOException e) {
System.out.println("聊天室结束了");
}finally {
listener.close();
}
}
}
/**
* TCP客户端
*/
public class ChatClient {
public static void main(String[] args) throws Exception {
//1创建socket
Socket socket=new Socket("xxxx.xxxx.xxxx.xxxx", 9999);
//2 获取输出流
OutputStream os = socket.getOutputStream();
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(os));
//3发送
Scanner input=new Scanner(System.in);
while(true){
String data = input.next();
bw.write(data);
bw.newLine();
bw.flush();
if(data.equals("拜拜")||data.equals("over")||data.equals("886")){
break;
}
}
//4关闭
bw.close();
socket.close();
}
}
*该聊天室只能实现一对多无差别的通信,如果需要在该聊天室中与特定的某个人聊天的话,该如何实现呢?
首先,我们应该知道并获取对方的IP地址,其次服务器应该实现对特定消息进行转发。具体实现如下:
//线程端
public class ChatThread extends Thread {
private Socket socket;
private Map<String,Socket> maps;
public ChatThread(Socket socket,Map<String,Socket> maps) {
this.socket = socket;
this.maps=maps;
}
@Override
public void run() {
BufferedReader br=null;
if(socket!=null){
try {
InputStream is = socket.getInputStream();
br=new BufferedReader(new InputStreamReader(is));
while(true){
String data = br.readLine();
if(data==null){
System.out.println(socket.getInetAddress().getHostAddress()+"退出了");
maps.remove(this.socket.getInetAddress().getHostAddress());
break;
}
System.out.println(socket.getInetAddress().getHostAddress()+"说:"+data);
if(data.equals("baibai")||data.equals("over")||data.equals("886")){
System.out.println(socket.getInetAddress().getHostAddress()+"退出了");
maps.remove(this.socket.getInetAddress().getHostAddress());
break;
}
//截取ip地址
String ip=data.substring(0, data.indexOf(":"));
String pattern = "((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}";
if(ip!=null){
boolean result = ip.matches(pattern);
if(result){
Socket socket = maps.get(ip);
if(socket!=null){
//转发
synchronized (socket){
OutputStream os = socket.getOutputStream();
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(os));
String address = this.socket.getInetAddress().getHostAddress();
bw.write(address+"说:"+data.substring(data.indexOf(":")+1));
bw.newLine();
bw.flush();
System.out.println(address+"给"+ip+"转发了数据");
}
}
}
}
}
} catch (Exception e) {
//e.printStackTrace();
//e.printStackTrace();
System.out.println(socket.getInetAddress().getHostAddress()+"异常退出了...");
maps.remove(this.socket.getInetAddress().getHostAddress());
}finally {
try {
br.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//服务器端
public class ChatServer {
public static void main(String[] args) throws IOException {
//1创建ServerSocket
ServerSocket listener = new ServerSocket(9999);
Map<String, Socket> maps = Collections.synchronizedMap(new HashMap<>());
//2监听
System.out.println("聊天服务器已启动....");
try {
while (true) {
Socket socket = listener.accept();
System.out.println("连接成功:" + socket.getInetAddress().getHostAddress());
maps.put(socket.getInetAddress().getHostAddress(), socket);
new ChatThread(socket, maps).start();
}
} catch (IOException e) {
System.out.println("聊天室结束了");
} finally {
listener.close();
}
}
}
//客户端
public class ChatClient {
public static void main(String[] args) throws Exception {
//1创建socket
Socket socket = new Socket("xxxx.xxxx.xxxx", 9999);
//2发送线程
new Thread(new Runnable() {
@Override
public void run() {
BufferedWriter bw = null;
try {
//2 获取输出流
OutputStream os = socket.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(os));
//3发送
Scanner input = new Scanner(System.in);
while (true) {
String data = input.nextLine();
bw.write(data);
bw.newLine();
bw.flush();
if (data.equals("baibai") || data.equals("over") || data.equals("886")) {
break;
}
}
//4关闭
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bw.close();
if (!socket.isClosed()) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
//3接受数据线程
new Thread(new Runnable() {
@Override
public void run() {
BufferedReader br = null;
try {
InputStream is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
while (true) {
String data = br.readLine();
System.out.println(data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
if (!socket.isClosed()) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
2.5TCP实现注册登录
//客户端
public class Client {
/**
* 注册
* @param userName 用户名
* @param password 密码
*/
public void doRegister(String userName,String password) {
realAction(userName, password, "10.31.165.42", 6666);
}
/**
* 登录
* @param userName 用户名
* @param password 密码
*/
public void doLogin(String userName,String password) {
realAction(userName, password, "10.31.165.42", 7777);
}
/**
* 将用户名和密码发送给服务端
* @param userName
* @param password
* @param ip
* @param port
*/
private void realAction(String userName,String password,String ip,int port) {
Socket client = null;
try {
//1.实例化一个Socket的对象
client = new Socket(ip, port);
//2.获取输出流
//缓冲字符流
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
//3.写入数据
writer.write(userName + "," + password);//yang123123abc
writer.flush();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//服务端
public class Server {
private ServerSocket registerSocket;// 用来注册
private ServerSocket loginSocket;// 用来登录
// 将每次需要注册的用户名和密码以键值对的形式存储到配置文件中,结合Properties使用
// 实例化一个Peroperties的对象
private Properties userlist = new Properties();
// 构造代码块
{
// 同步配置文件中的内容
try {
userlist.load(new BufferedInputStream(new FileInputStream(new File("file/userlist.properties"))));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 开启服务
*/
public void start() {
// 开启注册服务
new Thread() {
@Override
public void run() {
startRegisterService();
}
}.start();
// 开启登录服务
new Thread() {
@Override
public void run() {
startLoginService();
}
}.start();
}
/**
* 实现注册功能
*/
private void startRegisterService() {
try {
//1.实例化一个ServerSocket的对象
this.registerSocket = new ServerSocket(6666);
while(true) {
//2.获取连接到的客户端
Socket socket = this.registerSocket.accept();
System.out.println("连接到客户端" + socket);
//3.获取客户端发送来的数据
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//4.读取
String string = reader.readLine();//zhangsan,abc123
System.out.println(string);
//5.解析用户名和密码
String[] arr = string.split(",");
//6.注册
//arr[0]:用户名
//arr[1]:密码
if(this.userlist.containsKey(arr[0]) && this.userlist.containsValue(arr[1])) {
System.out.println("该用户已经存在,无需注册");
} else {
//新增一个用户
this.userlist.setProperty(arr[0], arr[1]);
//将用户名和密码同步到配置文件中进行持久化
this.userlist.store(new BufferedOutputStream(new FileOutputStream(new File("file/userlist.properties"))), "add an user");
System.out.println("注册成功");
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
try {
this.registerSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 实现登录功能
*/
private void startLoginService() {
try {
//1.实例化一个ServerSocket的对象
this.loginSocket = new ServerSocket(7777);
//2.获取连接到的客户端
Socket socket = this.loginSocket.accept();
//3.获取客户端发送来的用户名和密码
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//4.读取
String string = reader.readLine();
//5.解析用户名和密码
String[] arr = string.split(",");
//6.登录
if(this.userlist.containsKey(arr[0])) {
if(arr[1].equals(this.userlist.getProperty(arr[0]))) {
System.out.println("登录成功");
} else {
System.out.println("用户名/密码错误");
}
} else {
System.out.println("还未注册,请先注册");
//startRegisterService();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.UDP编程
3.1UDP基本概念
User Datagram Protocol的简称,用户数据包协议,提供面向事务的简单不可靠信息传送服务
特点:
1.不安全
2.无连接
3.效率高
4.UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内
3.2基于UDP的网络编程
3.2.1 客户端发送消息,服务端接收消息
public class Receiver {
public static void main(String[] args) throws Exception{
//创建DatagramSocket,指定端口号
DatagramSocket ds = new DatagramSocket(9999);
//创建一个接收的数据报包
byte[] bytes = new byte[1024*8];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//接收(阻塞方法,如果没有数据就阻塞,有数据就接收)
System.out.println("准备接收:");
ds.receive(dp);
//处理数据
String data = new String(dp.getData(),0,dp.getLength());
System.out.println(dp.getAddress().getHostAddress()+"对方说:"+data );
//关闭
ds.close();
}
}
public class Sender {
public static void main(String[] args) throws Exception {
//创建DatagramSocket,使用随机端口号
DatagramSocket ds = new DatagramSocket();
//创建发送数据报包
String say = "好久不见";
DatagramPacket dp = new DatagramPacket(say.getBytes(), say.getBytes().length, InetAddress.getLocalHost(), 9999);
//发送
ds.send(dp);
//接收回复
byte[] bytes = new byte[1024*8];
DatagramPacket dp2 = new DatagramPacket(bytes,bytes.length );
//关闭
ds.close();
}
}
3.2.2客户端发送消息,服务端回复消息
public class Receiver {
public static void main(String[] args) throws Exception{
//创建DatagramSocket,指定端口号
DatagramSocket ds = new DatagramSocket(9999);
//创建一个接收的数据报包
byte[] bytes = new byte[1024*8];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//接收(阻塞方法,如果没有数据就阻塞,有数据就接收)
System.out.println("准备接收:");
ds.receive(dp);
//处理数据
String data = new String(dp.getData(),0,dp.getLength());
System.out.println(dp.getAddress().getHostAddress()+"对方说:"+data );
//回复
String reply= "十分想念";
DatagramPacket dp2 = new DatagramPacket(reply.getBytes(),reply.getBytes().length,dp.getAddress(),dp.getPort() );
ds.send(dp2);
//关闭
ds.close();
}
}
public class Sender {
public static void main(String[] args) throws Exception {
//创建DatagramSocket,使用随机端口号
DatagramSocket ds = new DatagramSocket();
//创建发送数据报包
String say = "好久不见";
DatagramPacket dp = new DatagramPacket(say.getBytes(), say.getBytes().length, InetAddress.getLocalHost(), 9999);
//发送
ds.send(dp);
//关闭
ds.close();
}
}
3.2.3简易个人聊天室
public class ChatReceiver {
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket(9999);
byte[] bytes = new byte[1024 * 8];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
while (true) {
ds.receive(dp);
String data = new String(dp.getData(),dp.getLength());
System.out.println(dp.getAddress().getHostAddress() + "说:" + data);
if (data.equals("886")) {
System.out.println(dp.getAddress().getHostAddress() + "退出了");
}
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
ds.close();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket();
Scanner input = new Scanner(System.in);
while (true) {
String data = input.next();
DatagramPacket dp = new DatagramPacket(data.getBytes(), data.getBytes().length, InetAddress.getByName("10.9.21.255"), 9999);
ds.send(dp);
if (data.equals("886")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
ds.close();
}
}
}).start();
}
}