黑马程序员——网络编程(二)--TCP网络程序、访问Internet网络资源

-------  android培训java培训、期待与您交流! ----------

第一部分 TCP网络程序

一.TCP网络程序的工作原理

 

TCP客户端程序与TCP服务器程序的交互过程:

(1)服务器创建一个ServerSocket,然后调用accept方法等待客户来连接。

(2)客户端程序创建一个Socket并请求与服务器建立连接。

(3)服务器接收客户的连接请求,并创建一个新的Socket与该用户建立专线连接。

(4)建立了连接的两个Socket在一个单独的线程(由服务器程序创建)上对话。

(5)服务器等待新的连接请求,当新的连接请求到达时,重复步骤(2)到步骤(5)的过程。

二.ServerSocket

1.构造函数

1>public ServerSocket()

此种方法创建的ServerSocket对象不能直接使用,需要调用bind()方法设置完成后才可用

2>public ServerSocket(int port)

指定监听固定的口的连接请求。若port0,则系统自动分配一个空闲端口。

3>public ServerSocket(int port,int backlog)

backlog:当服务器很忙时,bakclog用于指定最大的正在等待的连接请求数量。当不显示指定这个参数时,默认值为50

4>public ServerSocket(int port,int backlog,InetAddress bindAddr)

bindAddr:当计算机上有多块网卡和 多个IPbindAddr参数用于指定其中某个为绑定IP.

2.close()方法

ServerSocket关闭,释放资源和ServerSocket占用的端口号

3.accept()方法

阻塞等待客户端的连接请求,一旦受到请求就返回一个与客户端建立连接的Socket对象。

三.Socket

1.构造函数:

1>public Socket()

Socket对象不能直接使用,需要调用connect()方法进行设置后才能用。

本构造方法用于同一个Socket对象轮循连接多个不同的服务器的情况。

2>public Socket(String host,int port)

3>public Socket(InetAddress addressint port)

上两个构造方法根据address,port参数连接指定的服务器地址和端口

4>public Socket(String host,int port,InetAddress localAddr,int localPort)

5>public Socket(InetAddress addressint port,InetAddress localAddr,int localPort)

localAddr,localPort参数指定本地的IP地址和端口。由于客户端的端口选择并不重要,因此这两种并方式不常用。当计算机有多个IP地址时,使用localAddr来指定连接的IP地址。当port值为0时,由计算机自动分配空闲端口。

2.getInputStreamgetOutputStream方法

当客户端和服务器端的两个Socket建立专线连接之后,他们以网络字节流的形式进行数据交换。通过这连个方法分别获取输入流对象和输出流对象。当向一端的Socket输出流对象写入数据时,另一端就能从输入流对象中读取到数据。

四.简单的TCP服务程序

(1)TCP服务器程序必须先启动运行,TCP客户端程序才能连接上TCP服务器

(1):实现一个服务器,当客户端与之连接时向其发送一句话,并接收客户端发来的一句话。

public class TcpServer {
	public static void main(String[] args) throws Exception {
		ServerSocket ss=new ServerSocket(8001);
		Socket s=ss.accept();
		InputStream ips=s.getInputStream();
		OutputStream ops=s.getOutputStream();
		ops.write("welcome to www.itcast.cn".getBytes());
		byte[] buf=new byte[1024];
		int len=ips.read(buf);
		System.out.println(new String(buf,0,len));
		ips.close();
		ops.close();
		s.close();
		ss.close();
	}
}

(2)使用Windows提供的telnet程序测试TCP服务器程序

(2):dos命令为:telnet {ip} {port}

(3)使用BufferredReader包装类,从网络输入流中一次读取一行文本

(3):在上面的程序中加入下面一段代码:

BufferedReader br=new BufferedReader(new InputStreamReader(ips));
	String strLine=br.readLine();
System.out.println(strLine);


(4)如何打来telnet程序的本地回显功能

(4):Windows命令行中进行如下设置:

telnet   //命令行进入telnet工具

set LOCAL_ECHO   //设置LOCAL_ECHO(本地回显)参数为开启

quit   //离开telnet设置状态

五.完善的TCP服务器程序模型

1.编程实例:

服务器程序能够同时与多个客户端会话,客户端每次向服务器发送一行字符文本,服务器就将这行字符文本中的所有字符反向排列后回送给客户端,当客户端向服务器发送的一行字符文本内容为”quit”时,服务器结束与客户端的会话。

2.编程要点:

1>TCP服务器程序要能接受多个客户端连接,需要循环调用ServerSocketaccept()方法。

2>服务器程序与每个客户端连接的会话过程不能互相影响,需要在独立的线程中运行。

3>一个线程服务对象与一个一个服务端Socket对象相关联,共同完成以一个客户的会话。

3.源代码:

public class TcpServer {
	public static void main(String[] args) {
		try {
			ServerSocket ss = new ServerSocket(8001);
			boolean bRunning=true;
			//每次接收一个客户端连接请求创建一个Socket对象和一个线程,并把这个Socket对象传到线程中
			while (bRunning) {
				Socket s = ss.accept();
				new Thread(new Server(s)).start();
			}
			ss.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
//用于与客户端进行交互会话的服务器端线程代码
class Server implements Runnable {
	private Socket s = null;
	public Server(Socket s) {
		this.s = s;
	}
	public void run() {
		try {
			InputStream ips = s.getInputStream();
			OutputStream ops = s.getOutputStream();
			BufferedReader bf = new BufferedReader(new InputStreamReader(ips));
			PrintWriter pw = new PrintWriter(ops, true);
			while (true) {
				String strLine = bf.readLine();
				if ("quit".equalsIgnoreCase(strLine))
					break;
				System.out.println(strLine + ":" + strLine.length());
				String strEcho = (new StringBuffer(strLine).reverse())
						.toString();
				pw.println(strLine + "-->" + strEcho);
			}
			bf.close();
			pw.close();
			s.close();
		} catch (Exception e) {
		}
	}
}

六.如何检测和解决端口冲突问题

1.使用netstat命令查看当前正在被使用的TCP端口号

2.通过命令行参数来指定TCP服务程序所使用的端口号

2:在上面的程序创建ServerSocket的代码改为:

<span style="white-space:pre">			</span>ServerSocket ss =null;
			if(args.length==1)
				ss=new  ServerSocket(Integer.parseInt(args[0]));
			else
				ss = new ServerSocket(8001);

在每次运行java命令时如果后面加上端口号则用此端口号,否则使用默认的8001端口。

3.将用户所指定的端口号保存到一个文件中,当服务器程序罅隙启动运行时,直接从文件中读取哪个端口号。

七.TCP客户端程序

1.编程实例:

编写一个与上面的服务器程序通信的客户端程序。

2.编程要点:

连接服务器的IP地址和端口号不要固定编写在程序代码中,而是通过程序的运行时参数来指定,以提供较高的通用性。

3.源代码:

public class TcpClient {
	public static void main(String[] args) throws Exception {
			Socket s=null;
			if(args.length==2)
				s=new Socket(args[0],Integer.parseInt(args[1]));
			else
				s=new Socket("127.0.0.1",8001);
			InputStream sips=System.in;
			InputStream ips=s.getInputStream();
			OutputStream ops=s.getOutputStream();
			BufferedReader sbr=new BufferedReader(new InputStreamReader(sips));
			BufferedReader br=new BufferedReader(new InputStreamReader(ips));
			PrintWriter pw=new PrintWriter(ops,true);
			while(true){
				String strLine=sbr.readLine();
				pw.println(strLine);
				if("quit".equalsIgnoreCase(strLine))
					break;
				String strEcho=br.readLine();
				System.out.println(strEcho);
			}
			sbr.close();
			br.close();
			pw.close();
			s.close();
	}
}

八.通过TCP程序在网络连接上传递对象

1.ObjectInputStreamObjectOutputStream可以从底层输入流中读取对象类型的数据和将对象类型的数据写入到底层输出流。

但所传递对象必须实现序列化接口Serializable。

2使用ObjectInputStreamObjectOutputStream来包装底层的网络字节流,TCP服务器和TCP客户端之间就可以传递对象类型的数据。

3.编程实例:通过网络传递一个Student类型的Java对象:

//定义用于创建被传递对象的类,要实现Serializable接口
public class Student implements Serializable{
	private Integer id;
	private String name;
	private Integer age;
	private String department;
	有参构造方法;
	所有属性的setter方法;
所有属性的getter方法;
toString();
}
//服务器段代码
public class ObjectServer {
	public static void main(String[] args) throws Exception {
		ServerSocket ss = new ServerSocket(8001);
		Socket s = ss.accept();
		OutputStream ops = s.getOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(ops);
		Student stu = new Student(4, "fda", 25, "computor");
		oos.writeObject(stu);
		oos.close();
		s.close();
		ss.close();
	}
}
//客户端代码
public class ObjectClient {
	public static void main(String[] args) throws Exception {
		Socket s = new Socket("127.0.0.1", 8001);
		InputStream ips = s.getInputStream();
		ObjectInputStream ois = new ObjectInputStream(ips);
		Student stu = (Student) ois.readObject();
		System.out.println(stu);
	}
}

4.怎样理解应用程序协议和网络通信协议的关系

TCP协议和FTP协议:TCP协议保证数据在网络中的传输。FTP协议用来实现文件在网络中的传输,是建立在TCP协议之中的协议。比如电话系统和人们之间的语言,电话系统好比TCP协议,而人们使用的不同语言则为应用程序协议,通话的双方必须约定好某种语言才能顺利实现通信。

5.怎样区分ASP,JSP与网络编程的概念

网络编程如同电视卫星系统,而TCPJSP如同制作电视节目,他们处于不同的领域。

第二部分 访问Internet网络资源

一.URL(Uniform Resource Locator)

1.URL的基本组成:协议、主机名、端口、资源名。

例如:http://www.itcast.cn:8080/index.html

2.相对URL,例如:”/a.html”,”./a.html”,”../../a.html”,”a.html”

相对URL要有基准URL

3.URL编码规则:

1>将空格转换为加号(+

2>0~9,a~z,A~Z之间的字符保持不变

3>对于所有其他的字符,用这个字符的当前字符集编码在内存中的十六进制格式表示,并在每个字节前加上一个百分号(%)。

如,字符’+’,用%2B表示,字符’=’用%3D表示,字符’&’用%26表示,每个中文字符在内存中占两个字节,字符’中’用%D6%D0表示,字符’国’用%B9%FA表示

4>对于空格也可以直接使用其十六进制编码方式,即用%26表示,而不是将他转换成加好(+)

4.java.net包中提供了URLEncoderURLDecoder这两个类来实现URL编码和解码。

二.HTTP协议会话过程

1.基于HTTP1.0协议的客户机与服务器的信息交换过程:

 

基于HTTP1.1协议的客户机与服务器的信息交换过程:

 

HTTP1.1中一个TCP连接可以有多个请求和响应减少了建立和关闭连接的消耗和延迟,提升了性能。一个包含多个图像的网页的多次请求和响应可以在一次连接中进行处理。

2.HTTP请求消息

一个完整的请求消息包括一个请求行、若干消息头、以及实体内容。

例如:

 

3.HTTP响应消息

一个完整的响应消息包括一个状态行、若干消息头、以及实体内容。

例如:

 

4.了解几个HTTP消息头

1>Connection:用于指定处理完本次请求响应后,客户端是否继续保持连接。设置值可以为Keep-Aliveclose

2>Accept-Language:用于支出客户机期望服务器返回的文档所使用的国家语言,可以指定多个以逗号分隔的国家语言。

3>Content-Length:用于表示实体内容的长度(字节数)

4>Range:用于指定服务器只需返回文档中的部分内容及内容范围,可以实现断点续传,有以下几种内容格式:

1)Range:bytes=100-599 //字节数是从零开始计算的,包含100599这连个字节

2)Range:bytes=100-

3)Range:bytes= -100

5>Content-Range:用于指定服务器返回的部分实体内容的位置信息,与请求的Range配合使用,例如:

Content-Type:bytes 2543-4532/7898

三.URL

1.构造函数(都可引发MalformedURLException异常):

--public URL(String spc)

--public URL(String protocol,String host,int port,String file)

--public URL(String protocol,String host,int port,String file,URLStreamHandler handler)

URLStreamHandler是协议处理器

--public URL(URL context,String spec)

2.getProtocolgetHostgetPortgetFile等方法

3.openConnection方法返回URLConnection对象。

4.URL类的setURLStreamHandlerFactory(URLStreamHandlerFactory fac)静态方法可为HTTP协议处理器,FTP协议处理器。若使用此方法应在所有的代码执行之前。

5.StreamHandlerFactory类的createURLStreamHandler(String protocol)方法。

6.工厂模式原理:

 

四.URLConnection类与HttpURLConnection类的作用

1.URLConnection类与HttpURLConnection类的访问:

用于向URL指向的资源中读取和写入数据。当访问不同URL资源时用不同的URLConnection子类,比如HTTP类资源用HttpURLConnection

2.URLConnection的连接过程

当产生URLConnection时,并没有真正的通过网络连接URL资源,在此之前可调用各种方法设置连接参数和响应。

3.setRequestProperty方法设置请求消息头

4.getHeaderField方法:当URLConnectionURL资源建立网络链之后,就可以调用get方法获取信息。

5.getInputStreamgetOutputStream方法

6.getHeaderField,getContentLength,getContentEncoding,getContentType方法,用于获取常用头信息。

7.一个HTTP连接可以被多个HttpURLConnection实例对象共享。调用HttpURLConnectiondisConnect方法可以关闭底层共享网络。

编程实例:将访问www.baidu.com站点的HTTP请求消息的Accept-Language头分别设置成日文和中文,然后打印出此站点返回的所有响应消息头和网络内容。

源代码:

public class GetBaidu {
	public static void main(String[] args) throws Exception{
		System.out.println("获取日文页面");
		getContentByLanguage("js");
		System.out.println("\n");
		
		System.out.println("获取中文页面");
		getContentByLanguage("zh-cn");
	}
	public static void getContentByLanguage(String country) throws Exception {
		URL urlBaidu = new URL("http://www.baidu.com");
		HttpsURLConnection bdConnection = (HttpsURLConnection) urlBaidu
				.openConnection();
		// 请求信息
		Map<String, List<String>> requests = bdConnection
				.getRequestProperties();
		Set<String> reqFields = requests.keySet();
		for (String reqField : reqFields) {
			System.out.println(reqField + " : "
					+ bdConnection.getRequestProperty(reqField));
		}
		// 响应信息
		Map<String, List<String>> responses = bdConnection.getHeaderFields();
		Set<String> resFields = responses.keySet();
		for (String resField : resFields) {
			System.out.println(resField + " : "
					+ bdConnection.getHeaderField(resField));
		}
		// 获得响应消息实体内容
		InputStream ips=bdConnection.getInputStream();
		BufferedReader br=new BufferedReader(new InputStreamReader(ips));
		String strLine=null;
		while((strLine=br.readLine())!=null){
			System.out.println(strLine);
		}
		br.close();
		bdConnection.disconnect();
	}
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值