黑马程序员---TCP传输

---------------------- ASP.Net+Unity开发、 .Net培训、期待与您交流! ----------------------

 

下载是TCP,因为如果下载到本地的文件,丢一点数据就解读不出来。
TCP
      建立连接,形成传输数据的通道。
      在连接中进行大数据量传输
      通过三次握手完成连接,是可靠协议
      必须建立连接,效率会稍低

面向连接,对方必须在,我先去确认对方的在,再去进行数据的发送。

怎么确认对方在?通过三次握手来确认。

 

TCP传输 :

客户端(Socket)服务端(ServerSocket)

 

java.net
Socket

此类实现客户端套接字。

构造方法摘要
  Socket()
          通过系统默认类型的 SocketImpl 创建未连接套接字
  Socket(InetAddress address, int port) 一new对象就连接。
          创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

 

  Socket(String host, int port)
          创建一个流套接字并将其连接到指定主机上的指定端口号。

空参数的构造函数通过以下方法建立连接:

 void connect(SocketAddress endpoint)
          将此套接字连接到服务器。

 

InetAddress getInetAddress()
          返回套接字连接的地址。

 

 

java.net
ServerSocket

此类实现服务器套接字。

构造方法摘要
ServerSocket() 没有绑定的,实行默认绑定,或者通过bind方法绑定。
          创建非绑定服务器套接字。
ServerSocket(int port) 一建立就绑定端口。
          创建绑定到特定端口的服务器套接字。

 

方法摘要
 Socket accept()
          侦听并接受到此套接字的连接。
 void bind(SocketAddress endpoint)
          将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
 void bind(SocketAddress endpoint, int backlog)
          将 ServerSocket 绑定到特定地址(IP 地址和端口号)。

 

演示TCP传输:

流程:
1.建立客户端和服务器端
2.建立连接后,通过Socket中的IO流进行数据的传输
3.关闭socket

同样,客户端与服务器端是两个独立的应用程序。

打电话是TCP传输:电话都有听筒和话筒。你用你的话筒说话,我用我的听筒听到。我用我的话筒说话,你用你的听筒听到。

客户端连接服务端,连接成功后,服务端就有了一个客户端对象。客户端用OutputStream给服务端发送请求,服务端用客户端对象的InputStream接收。服务端用客户端对象的OutputStream给客户端回馈信息,客户端用InputStream接收。

黑马程序员---TCP传输_第1张图片

 

/*
演示tcp传输。
1,tcp分客户端和服务端。
2,客户端对应的对象是Socket。
   服务端对应的对象是ServerSocket。
*/

import java.io.*;
import java.net.*;

/*
客户端,
通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。
因为tcp是面向连接的。所以在建立socket服务时,
就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。

需求:给服务端发送一个文本数据。

步骤:
1,创建Socket服务。并指定要连接的主机和端口。
*/
class TCPClient
{
	public static void main(String[] args) throws Exception
	{
		//建立客户端的Socket服务,指定目的主机和端口。
		Socket s = new Socket("192.168.1.100",10003);
		//如果这步成功了,通路就建立了。通路一建立,就有了一个Socket流(网络流)。
		//而这个Socket里面数据有读有写。所以Socket里面既有输入流也有输出流。
		//InputStream getInputStream() ,返回此套接字的输入流。 
		//OutputStream getOutputStream() ,返回此套接字的输出流。

		//为了发送数据,应该获取Socket的输出流。
		OutputStream out = s.getOutputStream();
		out.write("TCP wo lai la!".getBytes());
           
		s.close();
		//流不用关,因为流是随着Socket来的,Socket都没了,流肯定也没了。
	}
}

/*
需求:定义端点接收数据,并把数据打印在服务台上。

服务端:
1,建立服务端的socket服务。ServerSocket();
	并监听一个端口。
2,获取连接过来的客户端对象。
	通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。
	并打印在控制台。
4,关闭服务端。(可选)
*/
class TCPServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10003);
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"......connect");
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int length = in.read(buf);
		System.out.println(new String(buf,0,length));

		s.close();//关闭客户端。
		ss.close();//可选。
	}
}


必须先启动服务端

java TCPServer 命令之后,可查看到 10003 端口开着的状态:


黑马程序员---TCP传输_第2张图片

 

演示tcp的传输的客户端和服务端的互访

import java.net.*;
import java.io.*;
/*
演示tcp的传输的客户端和服务端的互访。
需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
*/
class TCPClient 
{
	public static void main(String[] args) throws Exception
	{
		//创建Socket服务,指定要连接的主机与端口。
		Socket s = new Socket("192.168.1.100",10004);

		//给服务端发送请求
		OutputStream out = s.getOutputStream();
		out.write("服务端:你好!".getBytes());
		
		//接收来自服务端的反馈信息,并打印到控制台。
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = 0;
		StringBuilder sb = new StringBuilder();
		while((len=in.read(buf))!=-1)
		{
			sb.append(new String(buf,0,len));
		}
		System.out.println(sb.toString());
		
		//关闭Socket服务。
		s.close();
	}
}

class TCPServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10004);

		Socket s = ss.accept();

		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"......connected");

		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		System.out.println(new String(buf,0,len));
		
		OutputStream out = s.getOutputStream();
		Thread.sleep(10000);
		out.write("我收到了,你也好!".getBytes());

		s.close();	
		ss.close();
	}
}

黑马程序员---TCP传输_第3张图片

 

需求:建立一个文本转换服务器。

客户端给服务端发送文本,服务端会将文本转成大写在返回给客户端。

而且客户端可以不断的进行文本转换。当客户端输入over时,转换结束。

java.lang
类 String

 String toUpperCase(Locale locale)
          使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。

 

import java.net.*;
import java.io.*;
/*
需求:建立一个文本转换服务器。
客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。
而且客户度可以不断的进行文本转换。当客户端输入over时,转换结束。
*/

class TCPClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.1.100",10005);
		
		//获取键盘录入
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		//获取Socket的输出流,给服务端发送消息。
		BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

		//获取Socket的读取流接收服务端反馈的信息。
		BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

		String line = null;
		while((line=br.readLine())!=null)
		{
			if(line.equals("over"))
			{
				break;
			}
			bufOut.write(line);
			bufOut.newLine();
			bufOut.flush();

			String str = bufIn.readLine();
			System.out.println("Server:"+str);
		}
		s.close();
		br.close();
	}
}

class TCPServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10005);

		Socket s = ss.accept();

		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+".......connected");

		BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
		BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

		String line = null;
		while((line=bufIn.readLine())!=null)
		{
			System.out.println(line);
			bufOut.write(line.toUpperCase());
			bufOut.newLine();
			bufOut.flush();
		}

		s.close();
		ss.close();
	}
}

黑马程序员---TCP传输_第4张图片

 

上传文件

需求:把客户端的一个文件数据发到服务端,在服务端把文件存起来

import java.net.*;
import java.io.*;

class TCPClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.1.100",10006);

		//读取本地文件
		File f = new File("Text.java");
		BufferedReader br = new BufferedReader(new FileReader(f));
		
		//网络发送流
		BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		
		String line = null;
		while((line=br.readLine())!=null)
		{
			bufOut.write(line);
			bufOut.newLine();
			bufOut.flush();
		}
		
		//结束标记
		s.shutdownOutput();
		
		//网络接收流
		BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
		String str = bufIn.readLine();
		System.out.println("Server:"+str);		

		s.close();
		br.close();
	}
}

class TCPServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10006);
		
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"......connected");

		//网络接收流
		BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
		
		//将收到的文件写到本地文件中。
		File f = new File("ZZZText.java");
		BufferedWriter bw = new BufferedWriter(new FileWriter(f));

		String line = null;
		while((line=bufIn.readLine())!=null)
		{
			bw.write(line);
			bw.newLine();
			bw.flush();
		}
		
		//给客户端发提示信息,表示上传成功。
		BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		bufOut.write("恭喜你,文件上传成功!");
		bufOut.flush();

		s.close();
		ss.close();
	}
}


黑马程序员---TCP传输_第5张图片

 

上传图片:

客户端将本地图片 上传到服务端,并保存到服务端硬盘。

import java.net.*;
import java.io.*;

class PicClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.1.100",10009);

		FileInputStream fi = new FileInputStream("cat.jpg");

		OutputStream out = s.getOutputStream();

		byte[] buf = new byte[1024];
		int len = 0;
		while((len=fi.read(buf))!=-1)
		{
			out.write(buf,0,len);
		}
		s.shutdownOutput();

		InputStream in = s.getInputStream();
		byte[] by = new byte[1024];
		int num = in.read(by);
		System.out.println(new String(by,0,num));

		fi.close();
		s.close();
	}
}

class PicServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10009);

		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"......connected");

		InputStream in = s.getInputStream();

		FileOutputStream fo = new FileOutputStream("D:\\cat4.jpg");

		byte[] buf = new byte[1024];
		int len = 0;
		while((len=in.read(buf))!=-1)
		{
			fo.write(buf,0,len);
		}

		OutputStream out = s.getOutputStream();
		out.write("上传成功".getBytes());

		fo.close();
		s.close();
	}
}

 

这个服务端有个局限性,当A客户端连接上之后,B客户端几连不进来,只有当A客户端的图片上传完之后关闭客户端Socket,B客户端才能连接上。

这个时候就需要给服务端封装多线程,使多个客户端可以并发上传图片。

TCP-客户端并发上传图片

import java.net.*;
import java.io.*;

class PicClient
{
	public static void main(String[] args) throws Exception
	{
		if(args.length!=1)
		{
			System.out.println("请选择一个.jpg文件");
			return ;
		}

		File file = new File(args[0]);

		if(!(file.exists() && file.isFile()))
		{
			System.out.println("文件有问题,要么不存在,要么不是文件");
			return ;
		}

		if(!file.getName().endsWith(".jpg"))
		{
			System.out.println("文件格式错误");
			return ;
		}

		if(file.length() > 1024*1024*5)
		{
			System.out.println("文件过大");
			return ;
		}

		Socket s = new Socket("192.168.1.100",10009);

		FileInputStream fi = new FileInputStream(file);

		OutputStream out = s.getOutputStream();

		byte[] buf = new byte[1024];
		int len = 0;
		while((len=fi.read(buf))!=-1)
		{
			out.write(buf,0,len);
		}
		s.shutdownOutput();

		InputStream in = s.getInputStream();
		byte[] by = new byte[1024];
		int num = in.read(by);
		System.out.println(new String(by,0,num));

		fi.close();
		s.close();
	}
}

class Server implements Runnable
{
	private Socket s;

	Server(Socket s)
	{
		this.s = s;
	}

	public void run()
	{
		String ip = s.getInetAddress().getHostAddress();
		try
		{
			int count = 1;

			InputStream in = s.getInputStream();

			File f = new File("D:\\"+ip+"("+count+").jpg");

			while(f.exists())
			{
				f = new File("D:\\"+ip+"("+count+++").jpg");
			}

			FileOutputStream fo = new FileOutputStream(f);
			byte[] buf = new byte[1024];
			int len = 0;
			while((len=in.read(buf))!=-1)
			{
				fo.write(buf,0,len);
			}

			OutputStream out = s.getOutputStream();
			out.write("上传成功".getBytes());

			fo.close();
			s.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException(ip+"上传失败");
		}
		
	}
}

class PicServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10009);
		while(true)
		{
			Socket s = ss.accept();

			Server ser = new Server(s);
			Thread t = new Thread(ser);
			t.start();
		}
	}
}

黑马程序员---TCP传输_第6张图片

 

 

 read 方法能不能到结尾,能不能停下来,关键看这个流是谁,是个文件那就能到结尾。

网络流的readLine方法,必须读到一个换行符,它才能停下来。所以在客户端必须加一个newLine,或者使用printWriter参数加个true自动刷新,println方法有换行功能。

客户端并发登录:

import java.io.*;
import java.net.*;
class TCPClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.1.100",10011);
	
		//定义键盘读取流
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		//定义网络输出流
		BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

		//定义网络读取流
		BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));

		//三次循环
		for(int x=0;x<3;x++)
		{
			//获取键盘录入的用户名
			String line = br.readLine();

			//判断,如果读到的字符串为null,说明服务端已使用快捷键ctrl+c关闭,客户端也应该果断跳出循环。
			if(line==null)
				break ;

			//发送到服务端
			out.write(line);
			out.newLine();
			out.flush();

			//接收服务端反馈信息,并打印。因为要在登录之后收到反馈信息,所以这个也在循环内
			String info = in.readLine();
			System.out.println(info);

			//判断,如果反馈回来的信息中包含“欢迎”字样,说明已经登录成功,这时应该跳出三次循环。
			if(info.contains("欢迎"))
				break;
		}

		//循环外关闭键盘读取流和Socket服务。
		br.close();
		s.close();
	}
}

class Server implements Runnable
{
	//成员数据
	private Socket s;

	//构造方法
	Server(Socket s)
	{
		this.s = s;
	}

	//run方法
	public void run()
	{
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"......connected");
		try
		{
			
			//三次循环
			for(int x=0;x<3;x++)
			{
				//定义网络接收流,接收客户端发来的用户名
				BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
				//网络流的readLine方法,必须读到一个换行符,它才能停下来。所以在发送端必须加一个newLine,或者使用printWriter参数加个true自动刷新。
				String line = in.readLine();

				//定义文件读取流
				BufferedReader br = new BufferedReader(new FileReader("user.txt"));

				//定义网络输出流
				BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

				//定义一个标记flag初始值为false
				boolean flag = false;

				//while循环读取文件中的用户名,
				String name = null;
				while((name=br.readLine())!=null)
				{			
					//对比接收的用户名和文件读取到的,如果发来的用户名在数据库里的一样,就将flag标记为true,并跳出读取文件循环。
					if(line.equals(name))
					{
						flag = true;
						break ;
					}
				}			

				//判断标记真假。如果flag为真,说明登录成功了,会给客户端回馈“欢迎光临”字样,并且跳出三次循环。
				if(flag)
				{
					System.out.println(ip+"已登录");
					out.write(ip+"欢迎光临");
					out.newLine();
					out.flush();
					break ;
				}
				//如果标记为假,说明用户名在数据库文件中没找到,登录失败,给客户端回馈信息“用户名不存在”,继续接收下一个从客户端发来的用户名,满三次自动结束循环。
				else
				{
					System.out.println(ip+"尝试登录");
					out.write(ip+"用户名不存在");
					out.newLine();
					out.flush();
				}			
			}

			//循环外关闭客户端。
			s.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException(ip+"校验失败");
		}		
	}
}

class TCPServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10011);

		while(true)
		{
			Socket s = ss.accept();
			new Thread(new Server(s)).start();
		}
	}
}

黑马程序员---TCP传输_第7张图片 

 

网络输出流 换成printWriter,它既可以 接收字节流,又可以 接收字符流,参数可以添加自动刷新功能,println方法代替write方法,并且有自动换行功能,省去了写newLine的麻烦。

import java.io.*;
import java.net.*;
class TCPClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.1.100",10011);
	
		//定义键盘读取流
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		//定义网络输出流,PrintWriter
		PrintWriter out = new PrintWriter(s.getOutputStream(),true);

		//定义网络读取流
		BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));

		//三次循环
		for(int x=0;x<3;x++)
		{
			//获取键盘录入的用户名
			String line = br.readLine();

			//判断,如果读到的字符串为null,说明服务端已使用快捷键ctrl+c关闭,客户端也应该果断跳出循环。
			if(line==null)
				break ;

			//发送到服务端
			out.println(line);
//			out.newLine();
//			out.flush();

			//接收服务端反馈信息,并打印。因为要在登录之后收到反馈信息,所以这个也在循环内
			String info = in.readLine();
			System.out.println(info);

			//判断,如果反馈回来的信息中包含“欢迎”字样,说明已经登录成功,这时应该跳出三次循环。
			if(info.contains("欢迎"))
				break;
		}

		//循环外关闭键盘读取流和Socket服务。
		br.close();
		s.close();
	}
}

class Server implements Runnable
{
	//成员数据
	private Socket s;

	//构造方法
	Server(Socket s)
	{
		this.s = s;
	}

	//run方法
	public void run()
	{
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"......connected");
		try
		{
			
			//三次循环
			for(int x=0;x<3;x++)
			{
				//定义网络接收流,接收客户端发来的用户名
				BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
				//网络流的readLine方法,必须读到一个换行符,它才能停下来。所以在发送端必须加一个newLine,或者使用printWriter参数加个true自动刷新。
				String line = in.readLine();

				//定义文件读取流
				BufferedReader br = new BufferedReader(new FileReader("user.txt"));

				//定义网络输出流
				PrintWriter out = new PrintWriter(s.getOutputStream(),true);

				//定义一个标记flag初始值为false
				boolean flag = false;

				//while循环读取文件中的用户名,
				String name = null;
				while((name=br.readLine())!=null)
				{			
					//对比接收的用户名和文件读取到的,如果发来的用户名在数据库里的一样,就将flag标记为true,并跳出读取文件循环。
					if(line.equals(name))
					{
						flag = true;
						break ;
					}
				}			

				//判断标记真假。如果flag为真,说明登录成功了,会给客户端回馈“欢迎光临”字样,并且跳出三次循环。
				if(flag)
				{
					System.out.println(ip+"已登录");
					out.println(ip+"欢迎光临");
//					out.newLine();
//					out.flush();
					break ;
				}
				//如果标记为假,说明用户名在数据库文件中没找到,登录失败,给客户端回馈信息“用户名不存在”,继续接收下一个从客户端发来的用户名,满三次自动结束循环。
				else
				{
					System.out.println(ip+"尝试登录");
					out.println(ip+"用户名不存在");
//					out.newLine();
//					out.flush();
				}			
			}

			//循环外关闭客户端。
			s.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException(ip+"校验失败");
		}		
	}
}

class TCPServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10011);

		while(true)
		{
			Socket s = ss.accept();
			new Thread(new Server(s)).start();
		}
	}
}

 

我们到现在已经写了很多客户端、服务端小程序了,

客户端、服务端无非就是个基于网络应用的程序而已,这样的程序在我们日程生活中碰到的有很多,

比如:浏览器就是个标准的客户端,我们既能做客户端又能做服务端,那么我们能不能做一个服务端,让浏览器访问呢?

浏览器客户端——自定义服务端

import java.net.*;
import java.io.*;

class ServerDemo 
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10012);

		Socket s = ss.accept();

		System.out.println(s.getInetAddress().getHostAddress());

		PrintWriter out = new PrintWriter(s.getOutputStream(),true);

		out.println("欢迎光临");

		s.close();
		ss.close();
	}
}

黑马程序员---TCP传输_第8张图片

 windows里面有一个远程登录命令:telnet

telnet是windows给我们提供的一个远程登录的工具,它可以连接网络中的任意一台主机,在dos命令行下连接,连接完以后可以对这台主机进行命令式的配置,比如说:远程登录去配置路由器和交换机。简单理解就是:telnet是一个客户端软件。

 默认没有安装的。 处理办法: 依次打开“开始”→“控制面板”→“打开或关闭Windows功能”,在打开的窗口处,寻找并勾选“Telnet客户端”,然后点击“确定”。顺利安装后,再在运行下输入此命令就OK了。

先开启服务端

黑马程序员---TCP传输_第9张图片

再输入此命令:

黑马程序员---TCP传输_第10张图片

telnet客户端收到数据:我们发现它把数据原封不动的显示出来了,因为HTML格式的数据它解析不了。

黑马程序员---TCP传输_第11张图片

 

浏览器客户端——Tomcat服务端

 双击startup.bat开启Tomcat

黑马程序员---TCP传输_第12张图片

 

 启动后

 黑马程序员---TCP传输_第13张图片

 在webapps文件夹新建一个myweb文件夹,并新建一个demo.html文件:

黑马程序员---TCP传输_第14张图片


	
		

这是我的主页

欢迎光临
哈哈哈哈哈
嘻嘻嘻喜爱
呵呵呵呵而

保存后,打开浏览器输入网址:http://192.168.1.102:8080/myweb/demo.html ,网页显示如下:

黑马程序员---TCP传输_第15张图片

 

 我们使用下面的代码得到浏览器给服务端到底发送了什么内容:

import java.net.*;
import java.io.*;

class ServerDemo 
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10012);

		Socket s = ss.accept();

		System.out.println(s.getInetAddress().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("客户端s你好");

		s.close();
		ss.close();
	}
}

这个就是浏览器给服务端发的HTTP请求消息头:请求消息头和请求消息体是有一个空行分隔符的,这个里面没有请求消息体。

黑马程序员---TCP传输_第16张图片

 现在浏览器发什么我们都知道了,我们是不是可以做一个自己的浏览器:

自定义浏览器——Tomcat服务端:

import java.net.*;
import java.io.*;

class MyIE 
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.1.100",8080);

		PrintWriter out = new PrintWriter(s.getOutputStream(),true);
		
		//向服务端发送HTTP请求消息头:
		out.println("GET /myweb/demo.html HTTP/1.1");
		out.println("Accept: */*");
		out.println("Accept-Language: zh-cn");
		out.println("Host: 192.168.1.100:8080");
		out.println("Connection: closed");
		
		//这里一定要记得写上空行分隔符,否则服务器不识别
		out.println();
		out.println();

		//接收服务端信息:
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = 0;
		while((len=in.read(buf))!=-1)
		{
			String str = new String(buf,0,len);
			System.out.println(str);
		}

		s.close();
	}
}

黑马程序员---TCP传输_第17张图片

 

自定义图形界面浏览器——Tomcat服务端:

 

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

class MyIEFrame 
{
	private Frame f;
	private Button b;
	private TextField tf;
	private TextArea ta;

	private Dialog d;
	private Button okButton;
	private Label label;
	
	MyIEFrame()
	{
		init();
	}

	public void init()
	{
		f = new Frame("my IE");
		tf = new TextField(70);
		b = new Button("转到");
		ta = new TextArea(32,78);

		f.setBounds(300,150,600,580);
		f.setLayout(new FlowLayout());

		f.add(tf);
		f.add(b);
		f.add(ta);

		d = new Dialog(f,"文件资源管理器",true);
		okButton = new Button("确定");
		label = new Label();

		d.setLayout(new FlowLayout());

		d.add(label);
		d.add(okButton);

		myEvent();

		f.setVisible(true);
	}

	public void myEvent()
	{
		//点击“关闭”按钮关闭对话框。
		d.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				d.setVisible(false);
			}
		});

		//点击“确定”按钮关闭对话框。
		okButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				d.setVisible(false);
			}
		});

		//敲“回车”获取文件列表内容。
		tf.addKeyListener(new KeyAdapter()
		{
			public void keyPressed(KeyEvent e)
			{
				if(e.getKeyCode()==e.VK_ENTER)
				{
					getList();
				}
			}
		});
		
		//点"转到"获取文件列表内容。
		b.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				getList();
			}
		});
	
		//点击“关闭”按钮关闭frame窗体。
		f.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);
			}
		});
	}

	private void getList()
	{
		ta.setText(null);

		//解析地址栏的网址
		//http://192.168.1.100:8080/myweb/demo.html
		String url = tf.getText();
		//int indexOf(String str)返回指定字符串在此字符串中第一次出现处的索引。
		int index1 = url.indexOf("//");
		//indexOf(String str, int fromIndex)
		int index2 = url.indexOf("/",index1+2);
		
		//substring(int beginIndex, int endIndex) 
		String substr = url.substring(index1+2,index2);
		
		//split(String regex)
		String[] arr = substr.split(":");
		String hostAddress = arr[0];
		int port = Integer.parseInt(arr[1]);

		try
		{
			//建立浏览器的客户端Socket服务
			Socket s = new Socket(hostAddress,port);

			PrintWriter out = new PrintWriter(s.getOutputStream(),true);
			
			//向服务端发送HTTP请求消息头:
			out.println("GET /myweb/demo.html HTTP/1.1");
			out.println("Accept: */*");
			out.println("Accept-Language: zh-cn");
			out.println("Host: 192.168.1.100:8080");
			out.println("Connection: closed");
			
			//这里一定要记得写上空行分隔符,否则服务器不识别
			out.println();
			out.println();

			//接收服务端信息:
			InputStream in = s.getInputStream();
			byte[] buf = new byte[1024];
			int len = 0;
			while((len=in.read(buf))!=-1)
			{
				String info = new String(buf,0,len);
				ta.append(info);
			}

			s.close();
		}
		catch (Exception ex)
		{
		}
	}

	public static void main(String[] args) 
	{
		new MyIEFrame();
	}
}

黑马程序员---TCP传输_第18张图片

响应头和主体信息之间也有空行。 

 

 ---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net

你可能感兴趣的:(黑马日志)