Server
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(10006);
Socket socket=null;
System.out.println("服务端已启动");
while(true){
socket=serverSocket.accept();
new Thread(new ServerThread(socket)).start();
}
}
}
ServerThread
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
public class ServerThread implements Runnable {
private Socket socket;
private int contentLength;
private View view=new View();
public ServerThread(Socket socket){
this.socket=socket;
}
@Override
public void run() {
try {
// while(true) {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream out = new PrintStream(socket.getOutputStream());
String tmp=reader.readLine();
//用浏览器访问时会请求图标,不处理这个请求
if(!tmp.contains("favicon")){
Request request = new Request();
request.parser(tmp);
while (!(tmp = reader.readLine()).equals("")) {
if (tmp.indexOf("Content-Length") != -1) {
contentLength = Integer.parseInt(tmp.substring(tmp.indexOf("Content-Length") + 16));
}
request.parser(tmp);
}
if (request.getMethod().equals("POST"))
getdata(reader, request);
view.display(out,request);
}
socket.close();
// break;//....这样的话。。。一个线程处理完一次HTTP请求就关闭了,没有实现长连接
// }
} catch (IOException e) {
e.printStackTrace();
}
}
private void getdata(BufferedReader reader, Request request) throws IOException {
//取得数据!
byte[] buf = {};
int size = 0;
if (contentLength != 0) {
buf = new byte[contentLength];
while(size<contentLength){
int c = reader.read();
buf[size++] = (byte)c;
}
String s=new String(buf, 0, size);
request.parserPostParameter(s);
}
}
}
Request
import java.util.ArrayList;
import java.util.HashMap;
/**
* HTTP请求的封装
*/
public class Request {
private String method;
private String protocol;// 协议版本
private String requestURI;
private String host;
private String Connection;//Http请求连接状态信息 对应HTTP请求中的Connection
private String agent;// 代理,标识浏览器信息,对应HTTP请求中的User-Agent:
private String language;//对应Accept-Language
private String encoding;
private String charset;
private String accept;// 对应Accept;
private HashMap<String,String> parameter;
public HashMap<String, String> getParameter() {
return parameter;
}
public void setParameter(HashMap<String, String> parameter) {
this.parameter = parameter;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public String getRequestURI() {
return requestURI;
}
public void setRequestURI(String requestURI) {
this.requestURI = requestURI;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getConnection() {
return Connection;
}
public void setConnection(String connection) {
Connection = connection;
}
public String getAgent() {
return agent;
}
public void setAgent(String agent) {
this.agent = agent;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getEncoding() {
return encoding;
}
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public String getAccept() {
return accept;
}
public void setAccept(String accept) {
this.accept = accept;
}
//暂时只支持get和post
public void parser(String s) {
if (s.startsWith("GET")) {
System.out.println(s);
String method = "GET";
setMethod(method);
int index = s.indexOf("HTTP");
String uri = s.substring(3 + 1, index - 1);// 用index-1可以去掉连接中的空格
setRequestURI(uri);
parserGetParameter(uri);
String protocol = s.substring(index);
setProtocol(protocol);
} else if(s.startsWith("POST")){
System.out.println(s);
String method = "POST";
setMethod(method);
int index = s.indexOf("HTTP");
String uri = s.substring(4 + 1, index - 1);
setRequestURI(uri);
String protocol = s.substring(index);
setProtocol(protocol);
}
else{
switch (s.substring(0,s.indexOf(":"))){
case "Accept":
String accept = s.substring("Accept:".length() + 1);
setAccept(accept);
break;
case "User-Agent":
String agent = s.substring("User-Agent:".length() + 1);
setAgent(agent);
break;
case "Host":
String host = s.substring("Host:".length() + 1);
setHost(host);
break;
case "Accept-Language":
String language = s.substring("Accept-Language:".length() + 1);
setLanguage(language);
break;
case "Accept-Charset":
String charset = s.substring("Accept-Charset:".length() + 1);
setCharset(charset);
break;
case "Accept-Encoding":
String encoding = s.substring("Accept-Encoding:".length() + 1);
setEncoding(encoding);
break;
case "Connection":
String connection = s.substring("Connection:".length() + 1);
setConnection(connection);
break;
}
}
}
/**
* 解析get方式请求的参数
* @param uri
*/
private void parserGetParameter(String uri) {
if(!uri.contains("?"))
return;
this.parameter=new HashMap<>();
uri=uri.substring(uri.indexOf("?")+1);
String[] list=uri.split("&");
for(String e:list){
String[] key_value=e.split("=");
parameter.put(key_value[0],key_value[1]);
}
}
/**
* post的参数解析必须外部手动调用。
* 知道这样做还有点蠢= =,时间紧迫
* @param s 形如username=%E7%A7%A6%E8%91%97&password=123
*/
public void parserPostParameter(String s){
if(s==null||s.length()==0)
return;
this.parameter=new HashMap<>();
String[] list=s.split("&");
for(String e:list){
String[] key_value=e.split("=");
if(key_value.length!=1)//kev_value==1时是提交空表单的情况
parameter.put(key_value[0],key_value[1]);
}
}
}
Service
import java.util.HashMap;
import java.util.Set;
/**
* 业务处理,
* 此处就是简单的登录和注册
*/
public class Service {
public static HashMap<String,String> users=new HashMap<>();
public static boolean register(Request request) {
HashMap<String,String> parameter=request.getParameter();
String username=parameter.get("username");
Set<String> un=users.keySet();
//账户已存在
if(un.contains(username)){
System.out.println("账户已存在");
return false;
}
String password=parameter.get("password");
String repassword=parameter.get("repassword");
if(password.equals(repassword)){
users.put(username,password);
return true;
}
System.out.println("两次密码不相同");
return false;
}
public static boolean login(Request request) {
HashMap<String,String> parameter=request.getParameter();
String username=parameter.get("username");
String password=parameter.get("password");
String pd=users.get(username);
if(pd==null||pd.equals("")||pd.length()==0)
return false;
if(!pd.equals(password))
return false;
return true;
}
}
View
import java.io.PrintStream;
/**
* 根据客户端的类型(控制台/浏览器)
* 显示页面或者简单字符
*/
public class View {
public void display(PrintStream out, Request request) {
String uri=request.getRequestURI();
boolean isBrowser=true;
//根据请求头里的Agent来判断是浏览器发出的请求还是控制台发出的请求
if (request.getAgent().contains("Qin.Z.Qin"))
isBrowser=false;
switch (uri){
case "/":
case "/index":
showLogin(out);
break;
case "/register":
showRegister(out);
break;
case "/saveUser":
if(Service.register(request))
showRegisterSuccess(out,isBrowser);
else
showRegisterFail(out,isBrowser);
break;
case "/login":
if(Service.login(request))
showLoginSuccess(out,isBrowser);
else
showLoginFail(out,isBrowser);
}
}
private void showLoginFail(PrintStream out,boolean isBrowser) {
String s="登录失败,请重试";
if(isBrowser)
s="<div class=\"jumbotron\">\n" +
" <h1>error!</h1>\n" +
" <p>please check your username and password</p>\n" +
" <p><a class=\"btn btn-primary btn-lg\" href=\"/index\" role=\"button\">Retry</a></p>\n" +
"</div>";
output(s,out,isBrowser);
}
private void showLoginSuccess(PrintStream out,boolean isBrowser) {
String s="登录成功";
if(isBrowser)
s="<div class=\"jumbotron\">\n" +
" <h1>login success!</h1>\n" +
" <p>This is Qin.Z.Qin's network program</p>\n" +
" <p><a class=\"btn btn-primary btn-lg\" href=\"/index\" role=\"button\">Home</a></p>\n" +
"</div>";
output(s,out,isBrowser);
}
private void showRegisterFail(PrintStream out,boolean isBrowser) {
String s="注册失败,请检查用户名和密码";
if(isBrowser)
s="<div class=\"jumbotron\">\n" +
" <h1>error!</h1>\n" +
" <p>This is Qin.Z.Qin's network program</p>\n" +
" <p><a class=\"btn btn-primary btn-lg\" href=\"/register\" role=\"button\">go back</a></p>\n" +
"</div>";
output(s,out,isBrowser);
}
/**
*
* @param out
* @param isBrowser 是否是浏览器在访问
*/
private void showRegisterSuccess(PrintStream out, boolean isBrowser) {
String s="注册成功";
if(isBrowser)
s="<div class=\"jumbotron\">\n" +
" <h1>register success!</h1>\n" +
" <p>This is Qin.Z.Qin's network program</p>\n" +
" <p><a class=\"btn btn-primary btn-lg\" href=\"/index\" role=\"button\">Home</a></p>\n" +
"</div>";
output(s,out,isBrowser);
}
private void showRegister(PrintStream out) {
String s="<div class=\"container\">\n" +
"\t<div class=\"row clearfix\">\n" +
"\t\t<div class=\"col-md-12 column\">\n" +
"\t\t\t<form role=\"form\" action=\"/saveUser\" method=\"post\">\n" +
"\t\t\t\t<div class=\"form-group\">\n" +
"\t\t\t\t\t <label for=\"exampleUsername1\">Username</label><input type=\"text\" name=\"username\" class=\"form-control\" id=\"exampleInputEmail1\" />\n" +
"\t\t\t\t</div>\n" +
"\t\t\t\t<div class=\"form-group\">\n" +
"\t\t\t\t\t <label for=\"exampleInputPassword1\">Password</label><input type=\"password\" name=\"password\" class=\"form-control\" id=\"exampleInputPassword1\" />\n" +
"\t\t\t\t\t <label for=\"exampleInputPassword1\">Repeat Password</label><input type=\"password\" name=\"repassword\" class=\"form-control\" id=\"exampleInputPassword2\" />\n" +
"\t\t\t\t</div>\n" +
"\t\t\t\t<div class=\"form-group\">\n" +
"\t\t\t\t</div> <button type=\"submit\" class=\"btn btn-default\">Submit</button>\n" +
"\t\t\t</form>\n" +
"\t\t</div>\n" +
"\t</div>\n" +
"</div>";
output(s,out,true);
}
/**
* 显示登录页
* @param out
*
*/
private void showLogin(PrintStream out) {
String s="<div class=\"container\">\n" +
"\t<div class=\"row clearfix\">\n" +
"\t\t<div class=\"col-md-12 column\">\n" +
"\t\t\t<form role=\"form\" action=\"/login\" method=\"post\">\n" +
"\t\t\t\t<div class=\"form-group\">\n" +
"\t\t\t\t\t <label for=\"exampleUsername1\">Username</label><input type=\"text\" name=\"username\" class=\"form-control\" id=\"exampleInputEmail1\" />\n" +
"\t\t\t\t</div>\n" +
"\t\t\t\t<div class=\"form-group\">\n" +
"\t\t\t\t\t <label for=\"exampleInputPassword1\">Password</label><input type=\"password\" name=\"password\" class=\"form-control\" id=\"exampleInputPassword1\" />\n" +
"\t\t\t\t</div>\n" +
"\t\t\t\t<div class=\"form-group\">\n" +
"\t\t\t\t</div> <button type=\"submit\" class=\"btn btn-default\">Submit</button>\n" +
"\t\t\t\t<button class=\"btn btn-default\" type=\"button\" onclick=\"window.open(\'/register\')\">register</button>"+
"\t\t\t</form>\n" +
"\t\t</div>\n" +
"\t</div>\n" +
"</div>";
output(s,out,true);
}
/**
* 给body添加上响应行,响应头
* @param s
* @param out
*/
private void output(String s, PrintStream out, boolean isBrowser) {
if(isBrowser){
out.println("HTTP/1.1 200 OK");
out.println("Content-Type:text/html;charset:UTF-8");
out.println();
s="<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><html><body>"+
"<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css\" integrity=\"sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO\" crossorigin=\"anonymous\">"+
s+
"</body></html>";
}
out.println(s);
out.flush();
out.close();
}
}
Client
import java.io.*;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;
/**
* 控制台客户端
* (推荐使用浏览器作为客户端)
*/
public class Client {
public static void main(String[] args) throws IOException {
boolean flag = true;
while(flag){
Socket socket=new Socket("127.0.0.1",10006);
socket.setSoTimeout(10000);
Scanner in =new Scanner(System.in);
PrintStream outer=new PrintStream(socket.getOutputStream());
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("欢迎使用粗陋的客户端,网页端地址:127.0.0.1:10006/index");
System.out.println("【1】:登录");
System.out.println("【2】:注册");
System.out.println("【3】:关闭");
System.out.println("请输入你的选择:");
int a=in.nextInt();
switch (a){
case 1:
login(in,outer,reader,socket);
break;
case 2:
register(in,outer,reader,socket);
break;
case 3:
System.exit(0);
default:
break;
}
}
}
private static void register(Scanner in, PrintStream outer, BufferedReader reader, Socket socket)
throws IOException {
String username,password,repassword;
System.out.println("输入用户名");
username=in.next();
System.out.println("输入密码");
password=in.next();
System.out.println("确认密码");
repassword=in.next();
HashMap<String,String> map=new HashMap<>();
map.put("username",username);
map.put("password",password);
map.put("repassword",repassword);
String request= buildPostRequest(socket,"/saveUser",map);
outer.println(request);
String echo="";
String tmp;
try {
while ((tmp=reader.readLine())!=null){
echo+=tmp;
}
} catch (SocketTimeoutException e) {
System.out.println("服务端响应超时");
}
System.out.println(echo+"\n\n");
}
private static void login(Scanner in, PrintStream outer, BufferedReader reader, Socket socket)
throws IOException {
String username,password;
System.out.println("请输入你的用户名");
username=in.next();
System.out.println("请输入你的密码");
password=in.next();
HashMap<String,String> map=new HashMap<>();
map.put("username",username);
map.put("password",password);
String request= buildPostRequest(socket,"/login",map);
outer.println(request);
String echo="";
String tmp;
try {
while ((tmp=reader.readLine())!=null){
echo+=tmp;
}
} catch (SocketTimeoutException e) {
System.out.println("服务端响应超时");
}
System.out.println(echo+"\n\n");
}
private static String buildPostRequest(Socket socket, String uri, HashMap<String, String> parameter) {
StringBuilder sb=new StringBuilder();
String requestBody="";
Set<String> keys=parameter.keySet();
for(String key:keys){
requestBody+=key+"="+parameter.get(key)+"&";
}
requestBody=requestBody.substring(0,requestBody.length()-1);
sb.append("POST "+uri+" HTTP/1.1\n");
sb.append("Host: "+socket.getInetAddress()+":"+socket.getPort()+"\n");
sb.append("Connection: keep-alive\n");
sb.append("Content-Length: "+requestBody.length()+"\n");
sb.append("Cache-Control: max-age=0\n");
sb.append("Upgrade-Insecure-Requests: 1\n");
sb.append("Content-Type: application/x-www-form-urlencoded\n");
sb.append("User-Agent: Qin.Z.Qin\n");
sb.append("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\n");
sb.append("Accept-Encoding: gzip, deflate, br\n");
sb.append("Accept-Language: zh-CN,zh;q=0.9\n");
sb.append("\n");
sb.append(requestBody);
return sb.toString();
}
}
参考一片很有用的帖子