最常见的客户端:浏览器,IE/chrome。
最常见的服务端:服务器,Tomcat。
2. 服务器原理
看一下向服务器发送了什么请求。
import java.io.IOException;
import java.io.*;
import java.net.*;
public class H_04ServerDemo
{
public static void main(String[] args) throws Exception
{
ServerSocket ss=new ServerSocket(11000);
Socket s=ss.accept();
System.out.println(InetAddress.getLocalHost().getHostAddress());
InputStream in=s.getInputStream();
byte [] buf=new byte[1024];
int len=in.read(buf);
System.out.println(new String(buf,0,len));
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("<font color='red' size='7'> 大家好</font>");
s.close();
ss.close();
}
}
运行后打开浏览器 http://192.168.0.100:11000/
显示红色7号字体的“大家好”
控制台打印以下信息:
192.168.0.100 GET / HTTP/1.1 Accept: image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-mfe-ipt, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.6,en;q=0.4,ja;q=0.2 Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; WOW64; Trident/7.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; McAfee; InfoPath.2) Host: 192.168.0.100:11000 Connection: Keep-Alive
|
这个是请求消息头。
协议 + 地址 + 端口 +路径+ 文件
请求头
GET / HTTP/1.1 发送get请求
//Accept: image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-mfe-ipt, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */
//支持的内容
/**
Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.6,en;q=0.4,ja;q=0.2
//支持的语言
Accept-Encoding: gzip, deflate
//压缩方式
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; WOW64;Trident/7.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; McAfee; InfoPath.2)
Host: 192.168.0.100:11000
主机名 和端口
Connection: Keep-Alive
//此处有空行
如果模拟将以上信息发送给服务器,就可以达到自定义浏览器的效果。
3. 自定义浏览器
import java.io.*;
import java.net.*;//我的ie客户端,需要tomcat支持
public class H_06MyIE {
public static void main(String[] args) throws Exception, IOException {
Socket s=new Socket("192.168.0.100",8080);
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("GET /myweb/demo.html HTTP/1.1" );//需要一个tomcat服务器 通过服务器访问 /myweb/demo.html
out.println("Accept: */*");
out.println("Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.6,en;q=0.4,ja;q=0.2");
out.println("Host: 192.168.0.100:11000");
out.println("Connection: Keep-Alive");
out.println();
out.println();
BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
s.close();
}
}
此处可以结合GUI,做一个建议IE程序,一个小文本框输入地址,一个文本区域显示得到的信息。
4. URL&URLConnection
URI:Uniform Resource Identifier统一资源标示符。
URL:Uniform Resoure Locator统一资源定位器,也就是说根据URL能够定位到网络上的某个资源,它是指向互联网“资源”的指针。
每个URL都是URI,但不一定每个URI都是URL。这是因为URI还包括一个子类,即统一资源名称(URN),它命名资源但不指定如何定位资源。
import java.net.*;
import java.io.*;
public class H_08URLConnection
{
public static void main(String[] args) throws Exception
{
URL url=new URL("http://www.sina.com");
sop(url.getProtocol());
sop(url.getHost());
sop(url.getPort());//不指定返回-1,此时要设定默认值80
sop(url.getPath());
sop(url.getFile());
sop(url.getQuery());
URLConnection urlc=url.openConnection();//返回内容不带应答信息,被解析了
//sop(urlc);
InputStream in=urlc.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf);
sop(new String(buf,0,len));
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
返回结果
http
www.sina.com
-1
null
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>@charset "utf-8";<style>body,div,span,p,iframe,a{margin:0;padding:0;outline:0}
.ad-dialog{position:absolute;z-index:998;padding:0;font-size:12px;overflow:hidden;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;box-shadow:1px 2px 2px #999;-webkit-box-shadow:1px 2px 2px #999;-moz-box-shadow:1px 2px 2px #999}.ad-dialog .title{width:100%;height:25px;line-height:25px;text-align:left;text-indent:8px;font-size:12px;font-weight:bold;color:#FFF;background:#CCC;-webkit-border-top-left-radius:4px;-moz-border-top-left-radius:4px;border-top-left-radius:4px;-webkit-border-top-right-radius:4px;-moz-border-top-right-radius:4px;border-top-right-radius:4px}.ad-dialog .icon{position:absolute;top:0;right:0;margin-right:4px}.ad-dialog .icon a{width:20px;height:20px;
5. 常见网络结构
1、C/S client/server
特点: 该结构的软件,客户端和服务端都需要编写。
开发成本较高,维护较为麻烦。
好处: 客户端在本地可以分担一部分任务。例如,杀毒软件直接对本机文件进行杀毒。
2、B/S browser/server
特点: 该结构的软件,只开发服务器端,不开发客户端,因为客户端直接由浏览器取代。
开发成本相对低,维护更为简单。
缺点:所有运算都要在服务端完成。
6. 练习
传输图片,服务端结合多线程
/*
客户端
1、创建服务端点
2、读取客户端已有的图片数据
3、通过socket输出流将数据发给服务端
4、读取服务端反馈信息
5、关闭
*/
package day24;
import java.io.*;
import java.net.*;
public class H_01TcpJpgClient
{
public static void main(String[] args) throws Exception, Exception
{
Socket s=new Socket(InetAddress.getLocalHost(),10008);
//读取文件
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("copy.png"));
//输出到网络
PrintStream ps=new PrintStream(s.getOutputStream());
byte [] buf=new byte[1024];
int len=0;
while((len=bis.read(buf))!=-1)
{
ps.write(buf, 0, len);
}
s.shutdownOutput();//结束标记 否则不会结束
BufferedInputStream bisin=new BufferedInputStream(s.getInputStream());
byte[] bufin=new byte[1024];
int chs=bisin.read(bufin);
System.out.println(new String(bufin,0,chs));
bis.close();
s.close();
}
}
/*
服务端
有个局限性,当A客户端连接上以后,被服务端获取到,服务端执行具体流程
这时B客户端连接,只有等待。
因为服务端还没有处理完A客户端的请求,还有玄幻回来执行下次accept方法,所以暂时获取不到B客户端请求。
为了可以让多个客户端同时并发访问服务端
将每个客户端封装到一个单独的线程中,这样就可以同时处理多个客户端请求
如何定义该线程
把客户端封装进入线程
*/
package day24;
import java.io.*;
import java.net.*;
public class H_01TcpJpgServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss=new ServerSocket(10008);
while(true)//服务端一直开启
{
Socket s=ss.accept();
new Thread(new PicThread(s)).start();// 每次有连接都会创建一个线程
}
}
}
//所有的服务器都是这个方法,非常重要
class PicThread implements Runnable
{
private Socket s;
PicThread(Socket s)
{
this.s=s;
}
public void run()
{
String ip=s.getInetAddress().getHostAddress();//获取ip
int count=1;
try
{
BufferedInputStream bis=new BufferedInputStream(s.getInputStream());
//解决文件覆盖的问题
File file=new File(ip+count+".png");
while(file.exists())
file=new File(ip+count+++".png");
PrintStream ps=new PrintStream(new FileOutputStream(file));
byte[] buf=new byte[1024];
int len=0;
while((len=bis.read(buf))!=-1)
{
ps.write(buf, 0, len);
}
PrintStream psout=new PrintStream(s.getOutputStream());
psout.write("上传成功".getBytes());
ps.close();
s.close();
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
}