服务器端多线程技术
应用java的多线程技术可以实现多个客户端向服务器端上传文件:
客户端:
public class UploadClient {
public static void main(String[] args) throws IOException {
//1. 创建socket客户端对象
Socket s=new Socket("127.0.0.1",10005);
//2. 读取图片文件
FileInputStream fis=new FileInputStream("F:\\1.jpg");
BufferedInputStream bufis=new BufferedInputStream(fis);
//3.获取socket输出流,将读到图片发送给服务器端
OutputStream out=s.getOutputStream();
int ch=0;
while((ch=bufis.read())!=-1){
out.write(ch);
}
//告知服务端数据发送完毕
s.shutdownOutput();
//读取服务端发回的上传成功
BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
String str=bufIn.readLine();
System.out.println(str);
bufis.close();
s.close();
}
}
服务器端:
public class UploadServer {
public static void main(String[] args) throws IOException {
//1. 创建serversocket服务
ServerSocket ss=new ServerSocket(10005);
while(true){//不断接收客户端
//2. 获取客户端
Socket s=ss.accept();
new Thread(new UploadTask(s)).start();
}
// ss.close();
}
}
服务器端线程处理类:
public class UploadTask implements Runnable {
private Socket s;
public UploadTask(Socket s){
this.s=s;
}
@Override
public void run() {
int count=0;
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+" connected");
try{
//3. 读取客户端发过来的数据(源)
BufferedInputStream bufIn=new BufferedInputStream(s.getInputStream());
//4. 写出到服务端的文件中(目的)
File dir=new File("f:\\pic");
if(!dir.exists())
dir.mkdirs();
File file=new File(dir,ip+".jpg");
//如果文件已经存在于服务器端
while(file.exists())
file=new File(dir,ip+"("+(++count)+").jpg");
BufferedOutputStream bufw=new BufferedOutputStream(new FileOutputStream(file));
int line=0;
while((line=bufIn.read())!=-1){
bufw.write(line);
}
//5. 告知客户端上传成功
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("上传成功");
bufw.close();
s.close();
}catch(IOException e){
}
}
}
客户端和服务器端原理
常见的客户端有IE浏览器。常见的服务器端有tomcat,它是一种web服务器。
服务器端原理
自定义服务端,使用已有的客户端IE,了解客户端给服务器端发了什么请求。
准备工作:首先电脑里要装tomcat服务器,再在webapps创建目录myweb,在myweb里创建文件1.html。
自定义服务器端:
public class MyTomat {
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(9090);
Socket s=ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+" connected");
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
String text=new String(buf,0,len);
System.out.println(text);
//给客户端一个反馈信息
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("<font color='red' size='7'>welcome to chengdu</font>");
s.close();
ss.close();
}
}
客户端给服务器端发送的请求为:
GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:9090
Connection: Keep-Alive
这些消息分成三个部分:请求行,请求消息头,请求体。
GET / HTTP/1.1
是请求行,包含三部分内容:1. 请求方式(get/post) 2. myweb/1.html 请求的资源路径 3. http协议版本
请求消息头的格式:属性名:属性值
Accept: text/html, application/xhtml+xml, image/jxr, */* //能够解析的数据类型
Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3 //支持的语言
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko //一些用户信息,系统版本等
Accept-Encoding: gzip, deflate //支持的压缩方式
Host: 127.0.0.1:9090 //访问的主机
Connection: Keep-Alive
请求体是自定义的信息。请求头和请求体之间必须有一行空行。
此时IE浏览器显示的内容为:
客户端原理
自定义一个浏览器,使用已有的服务器,了解服务器端给客户端端发了什么请求。
自定义浏览器:
public class MyBrowser {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket s=new Socket("127.0.0.1",8080);
//模拟浏览器,给tomcat服务端发送符合http协议的请求消息
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("GET /myweb/1.html HTTP/1.1");
out.println("Accept: text/html, application/xhtml+xml, image/jxr, */*");
out.println("Host: 127.0.0.1:8080");
out.println("Connection: close");
out.println();
out.println();
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
String str=new String(buf,0,len);
System.out.println(str);
s.close();
}
}
服务器端给客户端发送的应答消息为:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"189-1511429543426"
Last-Modified: Thu, 23 Nov 2017 09:32:23 GMT
Content-Type: text/html
Content-Length: 189
Date: Fri, 24 Nov 2017 02:34:55 GMT
Connection: close
<html>
<head>
<title>it's my page</title>
<head>
<body>
<h1>welcome to my page</h1>
<font size='5' color ='red'>html webpage source in tomcat</font>
</body>
</html>
第一行HTTP/1.1 200 OK
是应答行,由三部分内容组成:1. http的协议版本 2. 应答状态码(200表示成功,404表示not found) 3. 应答状态描述信息。
应答消息属性信息。格式为 属性名:属性值
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"189-1511429543426"
Last-Modified: Thu, 23 Nov 2017 09:32:23 GMT
Content-Type: text/html
Content-Length: 189
Date: Thu, 23 Nov 2017 09:33:06 GMT
Connection: close
再是应答消息体:
<html>
<head>
<title>it's my page</title>
<head>
<body>
<h1>welcome to my page</h1>
<font size='5' color ='red'>html webpage source in tomcat</font>
</body>
</html>
应答消息属性信息(应答头)和应答体之间有一行空行。
URL类
在我们自己模拟的浏览器中,服务器返回的应答消息包含应答行,应答消息头,应答体三个部分的信息,但是在真正的浏览器里,我们却只看到应答体部分的信息,这是由于浏览器自身具备解析http协议的能力,在应用层具备一个解析引擎,所以浏览器将应答消息头的部分给解析了,又在应答消息头解析的时候看到了应答消息体的解析方式,所以把应答消息体也解析为我们在浏览器中看到的样子,而不是HTML文本。
我们也可以自定义一个类似的解析引擎,将应答消息头解析。
URL地址包含着很多信息,可以封装成一个对象来解析,获取协议、端口、ip地址等等信息。
URL代表统一资源定位符,是一种URI(统一资源标识符),URI还包含URN(同一资源名称)。
URL不仅可以获取协议、端口等等信息,还可以通过openStream方法打开此URL的连接并返回一个用于从该连接读入的InputStream。通过这个就可以将应答消息解析掉。
public class URLDemo {
public static void main(String[] args) throws IOException {
String str_url="http://127.0.0.1:8080/myweb/1.html?name=lisa";
URL url=new URL(str_url);
// getInfo(url);
InputStream in=url.openStream();//原理url.openConnection().getInputStream();
//获取URL对象的URL连接器对象。将连接封装成了对象,这个对象就是java内置的可以解析的具体协议的对象+socket
// URLConnection conn =url.openConnection();
// InputStream in=conn.getInputStream();
// System.out.println(conn);//sun.net.www.protocol.http.HttpURLConnection:http://127.0.0.1:8080/myweb/1.html?name=lisa
//
// String value=conn.getHeaderField("Content-Type");//文本类型
// System.out.println(value);//text/html 启动指定的解析器来解析数据
//
byte[] buf=new byte[1024];
int len=in.read(buf);
String text=new String(buf,0,len);
System.out.println(text);
in.close();
}
/**
* @param url
*/
public static void getInfo(URL url) {
System.out.println("getProtocol:"+url.getProtocol());
System.out.println("getHost:"+url.getHost());
System.out.println("getPort:"+url.getPort());
System.out.println("getFile:"+url.getFile());
System.out.println("getPath:"+url.getPath());
System.out.println("getQuery:"+url.getQuery());
}
}
输出的是:
<html>
<head>
<title>it's my page</title>
<head>
<body>
<h1>welcome to my page</h1>
<font size='5' color ='red'>html webpage source in tomcat</font>
</body>
</html>
只有应答体了。
常见的网络结构
C/S client/server
特点:该结构的软件,客户端和服务端都需要编写。
缺点:开发成本较高,维护较为麻烦。
优点:客户端在本地可以分担一部分运算。B/S browser/server
特点:该结构的软件,只开发服务端,不开发服务器端,因为客户端直接由浏览器取代。
优点:开发成本相对低,维护更为简单。
缺点:所有运算都要在服务器端完成。