利用TCP原理来模拟C/S模型,实现多个客户端访问服务器端。
主要是通过在服务端实现多线程来实现。
主要步骤:
服务器端:
1.创建服务器端,指定端口。
2.调用accept方法,.阻塞式等待客户端连接
3.通过IO流拿到服务端的请求数据,并且对其分析。
4.再通过IO流把分析好后的数据发送出去。(对客户端的响应)
5.释放此次和这个客户端有关的资源。
2,3,4,5是在新的线程里运行,所以可以有多个客户端去请求访问。
客户端:
1.创建一个客户端,指定要访问呢的IP地址和端口号。
2.建立连接后,通过IO流向服务器端发送请求数据。
3.通过IO流,接收到服务端的响应数据。
4.释放此次的相关资源,结束请求。
代码:
package cn.liu.tcp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
/**
* 模拟:服务器端
* 1.可以支持访问响应
* 2.也可以支持多个客户端访问
* @author Administrator
*/
public class Server03{
private ServerSocket server;
private int port;
public Server03(int port) throws Exception {
this.port = port;
this.server = new ServerSocket(port);
}
//服务器对客户端的响应
public void work() throws Exception {
/**
* 错误:这只会有一个连接,一直在循环单线程内容。
* Socket client = server.accept();//阻塞式等待连接
* System.out.println("连接成功");
* while(true){
* new Thread(new response(client)).start();
* }
*/
while(true) {
Socket client = server.accept();//阻塞式等待连接
System.out.println("连接成功");
new Thread(new response(client)).start();
}
}
}
//Server的响应封装为一个类,方便多线程。
class response implements Runnable{
private Socket client;
public response(Socket client) {
super();
this.client = client;
}
@Override
public void run() {
try {
//拿到客户端的请求数据
DataInputStream is = new DataInputStream(client.getInputStream());
//对请求数据进行处理
String data = is.readUTF();
String[] datas = data.split("&&");
//String[] datas = is.readUTF().split("&&");
String str = null;
if(datas[0].equals("liu") && datas[1].equals("123456")) {
str = "用户名正确!\n密码正确!\n欢迎登录!";
}else {
str = "用户名或密码错误!";
}
//对请求数据做出响应,返回给客户端
DataOutputStream os = new DataOutputStream(client.getOutputStream());
os.writeUTF(str);
os.flush();
//关闭相关资源
is.close();
os.close();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package cn.liu.tcp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* 模拟登录:
* 1.可以支持访问响应
* 2.也可以支持多个客户端访问
* @author Administrator
*/
public class Client03{
private String ip;
private int serverPort;
private Socket client;
public Client03(String ip, int serverPort) throws Exception{
super();
this.ip = ip;
this.serverPort = serverPort;
this.client = new Socket(ip,serverPort);
}
public void request() throws Exception {
//向服务器发送请求数据
Scanner storage = new Scanner(System.in);
System.out.println("输入你的名字:");
String uname = storage.nextLine();
System.out.println("输入你的密码:");
String upassword = storage.nextLine();
DataOutputStream os = new DataOutputStream(client.getOutputStream() );
os.writeUTF(uname+"&&"+upassword);
os.flush();
//得到服务的响应数据
DataInputStream is = new DataInputStream(client.getInputStream());
String str = null;
str = is.readUTF();
System.out.println(str);
//关闭IO流,关闭连接
os.close();
is.close();
client.close();
}
}
测试:
//一个服务端
public static void main(String[] args) throws Exception {
System.out.println("----------------Server-------------");
Server03 ss = new Server03(8848);
ss.work();
}
//多个客户端
public static void main(String[] args) throws Exception {
System.out.println("----------------client-------------");
Client03 aa = new Client03("Dick",8848);
aa.request();
}
public static void main(String[] args) throws Exception {
System.out.println("----------------client-------------");
Client03 bb = new Client03("Dick",8848);
bb.request();
}
效果:
自己思路方面遇到的问题:
1.如何判断这个输入输出的方向,即:IO流神魔时候用输出神魔时候输入。
最后发现输入就是:写到IO流中,通过内存写向硬盘或(服务器端)。输出就是通过内存从硬盘(服务器端)中拿到数据。
2.写完后程序一直出错,最后发现是服务器端有错。
//服务器对客户端的响应
public void work() throws Exception {
/**
* 错误:这只会有一个连接,一直在循环单线程内容。
* Socket client = server.accept();//阻塞式等待连接
* System.out.println("连接成功");
* while(true){
* new Thread(new response(client)).start();
* }
*/
while(true) {
Socket client = server.accept();//阻塞式等待连接
System.out.println("连接成功");
new Thread(new response(client)).start();
}
主要问题还是自己对这个Socket client = server.accept();//阻塞式等待连接。
阻塞式没有理解到位。如果没有建立连接就一直会等,现在要实现多线程支持多个客户端访问,那就也要多个连接,所以Socket client = server.accept(()也要放进while()循环体。