一、需求:
-
完成多用户网络登陆功能
-
用户输入用户名密码,服务器给出登陆成功或失败的提示
二、分析:
- 使用基于TCP协议的Socket网络编程实现
- TCP协议基于请求-响应模式
- 在网络通信中,第一次主动发起通讯的程序被称作客户端(Client)程序
- 第一次通知等待连接的程序被称为服务器端(Server)程序
- 利用IO流实现数据的传输
三、服务器端
思路
1、指定端口,使用ServerSocket创建服务器;
2、阻塞式等待连接(accept()方法);
3、通过I/O流获取数据并进行分析;
4、释放资源;
代码:
将具体的操作封装在一个内部类里,当有一个客户端连接服务器后都可以创建一个子线程来实现其功能;
public class TCPServer {
public static void main(String[] args) throws IOException {
// 1、指定端口,使用ServerSocket创建服务器
ServerSocket serverSocket = new ServerSocket(8888);
// 2、阻塞式等待连接 accept
boolean flag = true;
while (flag) {
Socket socket = serverSocket.accept();
System.out.println("有一个客户端连接了服务器");
new Thread(new Channel(socket)).start();
}
serverSocket.close();
}
static class Channel implements Runnable{
private Socket socket;
DataInputStream dis; //输入流
DataOutputStream dos; //输出流
public Channel(Socket socket) {
this.socket = socket;
try {
dis = new DataInputStream(this.socket.getInputStream());
dos = new DataOutputStream(this.socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
release();
}
}
@Override
public void run() {
System.out.println("客户端连接成功");
// 3、操作:输入输出流
String uName = "";
String uPwd = "";
//分析数据
String[] dataArray = receive().split("&");
for (String info : dataArray) {
String[] userInfo = info.split("=");
if (userInfo[0].equals("userName")) {
System.out.println("你的用户名为:" + userInfo[1]);
uName = userInfo[1];
} else {
System.out.println("你的密码为:" + userInfo[1]);
uPwd = userInfo[1];
}
}
//输出
if (uName.equals("daria") && uPwd.equals("123")) {
send("登录成功");
} else {
send("用户名或密码错误,请重新输入");
}
release();
}
//接收数据
private String receive() {
String datas = "";
try {
datas = dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
return datas;
}
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
//释放资源
private void release() {
try {
if (null != dos) {
dos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != dis) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != socket) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、客户端
思路:
1、建立连接 使用Socket创建客户端+服务器地址和端口;
2、通过I/O流向服务端发送数据或接收响应数据;
3、结束请求,释放资源;
代码:
将数据的发送和接收各自封装成一个内部类里,方便维护;
public class TCPClient {
static class Send { //发送消息
private DataOutputStream dos;
private Socket socket;
private Scanner scanner;
private String msg;
public Send(Socket socket) {
this.scanner = new Scanner(System.in);
this.msg = this.init();
this.socket = socket;
try {
dos = new DataOutputStream(this.socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
private void send() {
try {
dos.writeUTF(this.msg);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private String init() {
System.out.println("请输入用户名");
String userName = this.scanner.nextLine();
System.out.println("请输入密码");
String userPwd = this.scanner.nextLine();
return "userName=" + userName + "&" + "userPwd=" + userPwd;
}
}
static class Receive { //接收消息
private DataInputStream dis;
Socket socket;
public Receive(Socket socket) {
this.socket = socket;
try {
dis = new DataInputStream(this.socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void receive() {
String result = null;
try {
result = dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(result);
}
}
public static void main(String[] args) throws IOException {
// 1、建立连接 使用Socket创建客户端+服务器地址和端口
Socket socket = new Socket("127.0.0.1",8888);
// 2、操作:输入输出流
new Send(socket).send();
new Receive(socket).receive();
// 3、释放资源
socket.close();
}
}
五、测试
因为没有连接数据库无法判定输入的用户名跟密码是否正确,所以在这里就指定了用户名daria和密码123来对输入的信息进行校验;