参考文档
https://www.sxt.cn/Java_jQuery_in_action/twelve-tcpsocket.html
参考视频
https://www.bilibili.com/video/BV1ct411n7oG?p=246
1.代码功能
1.实现多用户登录
2.学习重点
1.服务器端使用多线程使得多个客户端可以同时使用
2.封装:服务器端一个客户端一个channel,客户端服务器端都对收发消息进行封装,客户端将从键盘获取输入封装为init()初始化;服务器端对关闭资源封装,run方法里只操作业务逻辑(调用receive后分析数据,调用send返回结果)。
3.客户端代码
1.创建client
2.调用Send类,Receive类里的send,receive方法。
2.1Send类里包含client,dos等相关的属性,Send构造函数里包含业务逻辑,发送端的初始化,init()里包含console的初始化,send函数里就是单纯的发送消息。
2.2Receive类与Send类类似,包含client,dis等相关属性,Receive构造函数里包含client,dis的初始化,receive函数里就是单纯的接收消息。
3.关闭client
package com.sxt.tcp;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
/**
*模拟登录 多个客户端请求
* 创建客户端
* 1.建立连接:使用Socket创建客户端+服务的地址和端口
* 2.操作:输入输出流操作
* 3.释放资源
* @author Yangxiaoxia
*
*/
public class LoginMultiClient {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("-----Client-----");
//1.建立连接:使用Socket创建客户端+服务的地址和端口
Socket client=new Socket("localhost",8888);
//2.操作:输入输出流操作
new Send(client).send();
new Receive(client).receive();
client.close();
}
//发送
static class Send{
private Socket client;
private DataOutputStream dos;
private BufferedReader console;
private String msg;
public Send(Socket client) {
console =new BufferedReader(new InputStreamReader(System.in));
this.msg=init();
this.client=client;
try {
dos=new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String init() {
try {
System.out.print("请输入用户名:");
String uname=console.readLine();
System.out.print("请输入密码:");
String upwd =console.readLine();
return "uname="+uname+"&"+"upwd="+upwd;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return " ";
}
public void send( ) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//接收
static class Receive{
private Socket client;
private DataInputStream dis;
public Receive(Socket client) {
this.client=client;
try {
dis=new DataInputStream(client.getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void receive() {
String result;
try {
result = dis.readUTF();
System.out.println(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
4.服务器端代码
1.创建server
2.给参数isRuning,while循环里阻塞式等待连接,给客户端开启多线程
2.1一个Channel类代表一个客户端,继承Runnable接口,实现抽象方法run,run方法里处理业务逻辑,分析数据,返回结果,Channel类包含client,dis,dos属性 Channel构造函数包含 3个属性的初始化,以及client.close(),释放资源。send,receive,release方法分别是发送数据,接收数据,释放资源。
3.关服务器
package com.sxt.tcp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import org.omg.PortableInterceptor.DISCARDING;
/**
* 模拟登录 多个客户端请求
* 创建服务器
* 1.指定端口 使用ServerSocket创建服务器
* 2.阻塞式等待连接 accept
* 3.操作:输入输出流操作
* 4.释放资源
* @author Yangxiaoxia
*
*/
public class LoginMultiServer {
public static void main(String[] args) throws IOException {
System.out.println("------Server-------");
// 1.指定端口 使用ServerSocket创建服务器
ServerSocket server=new ServerSocket(8888);
boolean isRuning=true;
// 2.阻塞式等待连接 accept
while(isRuning) {
Socket client=server.accept();
System.out.println("一个客户端建立了连接");
new Thread(new Channel(client)).start();
}
server.close();
}
//一个channel 就代表一个客户端
static class Channel implements Runnable{
private Socket client;
//输入流
private DataInputStream dis;
//输出流
private DataOutputStream dos;
public Channel(Socket client) {
this.client=client;
try {
dis = new DataInputStream(client.getInputStream());
//输出
dos=new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
client.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
release();
}
}
}
//接收数据
private String receive() {
String datas="";
try {
datas = dis.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return datas;
}
//释放资源
private void release() {
try {
if(null!=dos) {
dos.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(null!=dis) {
dis.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(null!=client) {
client.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//发送数据
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
// 3.操作:输入输出流操作
String uname=" ";
String upwd=" ";
//分析
String[] dataArray=receive().split("&");
for(String info:dataArray) {
String[] userinfo=info.split("=");
if(userinfo[0].equals("uname")) {
System.out.println("你的用户名为:"+userinfo[1]);
uname=userinfo[1];
}else if(userinfo[0].equals("upwd")) {
System.out.println("你的密码为:"+userinfo[1]);
upwd=userinfo[1];
}
}
if(uname.equals("baidu")&& upwd.equals("123456")) {//成功
send("登陆成功,欢迎回来");
}else {//失败
send("用户名或密码错误");
}
release();
}
}
}