TCP网络编程服务端与客户端半关闭的流
程序员文章站
2022-06-30 18:20:58
...
最常见的客户端:
浏览器 :IE。
最常见的服务端:
服务器:Tomcat。
浏览器请求: 为什么要发送请求? 没有请求,服务器不知道你需要什么页面,什么内容,你能接受什么信息。
请求: 发送的请求是:请求消息 请求头 + 空行 + 请求体
请求消息头 属性名:属性值
GET /myweb/1.html HTTP/1.1 第一行请求行: 请求方式 请求的资源路径 协议版本
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash,
application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */ *
Accept-Language: zh-cn,zu;q=0.5
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)
Host: 192.168.1.100:9090
Connection: Keep-Alive
//空行
//请求体。
服务器应答 //服务端发回应答消息。
HTTP/1.1 200 OK //应答行,http的协议版本 应答状态码 应答状态描述信息
应答消息属性信息。 属性名:属性值
Server: Apache-Coyote/1.1
ETag: W/"199-1323480176984"
Last-Modified: Sat, 10 Dec 2011 01:22:56 GMT
Content-Type: text/html
Content-Length: 199
Date: Fri, 11 May 2012 07:51:39 GMT
Connection: close
//空行
//应答体。
<html>
<head>
<title>这是我的网页</title>
</head>
<body>
<h1>欢迎光临</h1>
<font size='5' color="red">这是一个tomcat服务器中的资源。是一个html网页。</font>
</body>
</html>
// 自定义浏览器;模拟浏览器
public static void main(String[] args) throws UnknownHostException, IOException {
// 访问 192.168.1.100:8080 服务器
Socket s = new Socket("192.168.1.100",8080);
//访问http://192.168.1.100:8080/myweb/1.html
//模拟浏览器,给tomcat服务端发送符合http协议的请求消息。告诉浏览器我需要什么。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("GET /myweb/1.html HTTP/1.1");
out.println("Accept: */*");
out.println("Host: 192.168.1.100:8080"); //访问的主机
out.println("Connection: close");
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();
}
自定义服务器: 模拟服务器
public class MyTomcat {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// 建立服务器socket 明确端口
ServerSocket ss = new ServerSocket(9090);
while(true) {
多线程并发访问。
Socket s= ss.accept();
new Thread(new Threadtext(s)).start();
// http://115.158.64.36:9090/
}
}
}
/线程任务
class Threadtext implements Runnable{
Socket s;
public Threadtext(Socket ss) {
super();
this.s = ss;
}
public void run() {
String ip = s.getInetAddress().getHostAddress();
try {
/ 获得浏览器请求
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(ip);
System.out.println("*********************");
System.out.println(text);
//给客户端一个反馈信息。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("<font color='red' size='50'> 109 的大帅比 109 的大帅比 109 的大帅比 109 的大帅比 109 的大帅比 109 的大帅比</font>");
s.close();
}catch(Exception E) {
}
}
}
浏览器模拟
URL 对象与 URLConnection对象: 类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。
类 URLConnection 将 连接 封装成了对象:java中内置的可以解析的具体协议的对象 + socket.封装为对象。解析URL并发送URL请求。
public static void main(String[] args) throws IOException {
String str_url = "http://192.168.1.100:8080/myweb/1.html";
类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针 ,此处并没有连接
URL url = new URL(str_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());
// InputStream in = url.openStream();
获取url对象的Url连接器对象。将连接封装成了对象:java中内置的可以解析的具体协议的对象+socket.
建立socket 并发送请求信息。
URLConnection conn = url.openConnection();
// String value = conn.getHeaderField("Content-Type");
// System.out.println(value);
// System.out.println(conn);
//sun.net.www.protocol.http.HttpURLConnection:http://192.168.1.100:8080/myweb/1.html
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
in.close();
}
服务端
public class Server
{
public static void main(String[] args)
throws IOException
{
// 创建一个ServerSocket,用于监听客户端Socket的连接请求
ServerSocket ss = new ServerSocket(30000);
// 采用循环不断接受来自客户端的请求
while (true)
{
// 每当接受到客户端Socket的请求,服务器端也对应产生一个Socket
Socket s = ss.accept();
// 将Socket对应的输出流包装成PrintStream
PrintStream ps = new PrintStream(s.getOutputStream());
// 进行普通IO操作
ps.println("您好,您收到了服务器的新年祝福!");
// 关闭输出流,关闭Socket
ps.close();
s.close();
}
}
}
客户端
public class Client
{
public static void main(String[] args)
throws IOException
{
Socket socket = new Socket("127.0.0.1" , 30000); // ①
// 将Socket对应的输入流包装成BufferedReader
BufferedReader br = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
// 进行普通IO操作
String line = br.readLine();
System.out.println("来自服务器的数据:" + line);
// 关闭输入流、socket
br.close();
socket.close();
}
}
半关闭的Socket
public static void main(String[] args)
throws Exception
{
ServerSocket ss = new ServerSocket(30000);
Socket socket = ss.accept();
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("服务器的第一行数据");
ps.println("服务器的第二行数据");
// 关闭socket的输出流,表明输出数据已经结束
socket.shutdownOutput();
// 下面语句将输出false,表明socket还未关闭。
System.out.println(socket.isClosed());
Scanner scan = new Scanner(socket.getInputStream());
while (scan.hasNextLine())
{
System.out.println(scan.nextLine());
}
scan.close();
socket.close();
ss.close();
}
- URLConnection 和socket都是一站式的响应,socket当关闭流以后socket也将关闭,不适合保持持久通信的状态,只适用于请求一次相应一次。当相应完成以后,socket也将关闭。而URLConnection 也式通样。