您的位置:首页 > 理论基础 > 计算机网络

黑马程序员--10.网络编程--06.【Clinet_Server通信原理】【TCP_客户端和服务端会话】【阻塞式方法的详解】

2013-08-29 00:02 736 查看

网络编程--6

C/S通信原理(Client/Server)

TCP客户端和服务端会话 

阻塞式方法详解

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

1.    C/S通信原理

1). 服务器端的特点

(1). 一个服务端的存在可以允许接入多个客户端

(2). Server端和单个Client端通信过程

{1}. 服务端ServerSocket对象本身没有流对象, 但是客户端Socket对象本身对象。

{2}. 但是一旦某个客户端服务端建立了连接之后服务端会通过自身的accept方法获取到这个客户端通信端点Socket对象的副本,并使用这个Socket副本真实的客户端对象进行通信

e.g.

ServerSocket ss =new ServerSocket(10003); Socket s =ss.accept();


Socket s=ss.accept();使得ServerSocket端点获取到了客户端Socket的副本

因此在服务端的程序仅仅是通过ServerSocket对象获取到连接进来的Client的Socket对象之后,便是用这个Socket进行通信。

2). C/S通信原理

一个Server端多个Client端进行通信的原理。

(1). 一个Server端和多个Client端的通信原理图



(2). 通信过程分析

[1]. 客户端Socket A对象Server端发了一个请求。假设此时连接成功。Server端便会通过自身的accept()方法获取客户端A的副本Socket对象

[2]. A对象本身有输入流对象in输出流对象out,因此在Server端A对象的副本同样也有in和out两个对象

[3]. 从客户端A服务端Server发送数据

客户端A对象通过自身的outServer端发送出数据,此时Server端使用A对象的副本in对象进行数据的读取

[4]. 客户端A服务端Server读取数据

Server端向给客户端A发出回馈信息,就通过A的副本输出流对象out发出信息。此时客户端A通过自身的输入流对象in将Server端发送给自己的反馈信息读取进来

[5]. 如果此时客户端C也连接到Server端,那么通信过程也是Server端C的副本和客户端的对象C进行通信。

[6]. 每个客户端在服务器端都有一个映像来和自己进行通信,因此各自进行自己的通信,不会混淆

2.    TCP客户端和服务端会话

1). TCP客户端通信

(1). 客户端需求

客户端先向服务器发送数据,之后再从服务器获取反馈信息并把反馈信息打印在控制台上。

(2). 客户端会话代码示例

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

class TcpClient2{
public static void main(String[] args)throws Exception{
//向服务器发送数据
Socketsocket =new Socket("127.0.0.1", 10004);
OutputStreamout =socket.getOutputStream();
out.write("Hi Server, I amClient...".getBytes());

//从服务端接收数据
InputStreamin =socket.getInputStream();
byte[] buf =newbyte[1024];
int len = in.read(buf);
System.out.println("Server replied: "+new String(buf, 0, len));
}
}


2). TCP服务器端通信
(1). 服务端需求

服务端先从客户端接受数据,之后再向客户端发送相应的反馈信息。

(2). 服务端会话代码示例

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

class TcpServer2{
public static void main(String[] args)throws Exception{
//接受客户端的连接请求并读出客户端的信息
ServerSocketss =new ServerSocket(10004);
SocketclientSocket =ss.accept();
Stringip =clientSocket.getInetAddress().getHostAddress();
System.out.println(ip+"...connected!");
InputStreamin =clientSocket.getInputStream();

byte[] buf =newbyte[1024];
int len =in.read(buf);
System.out.println("The message sent from Clientis :"+new String(buf, 0, len));

Thread.sleep(5000);

OutputStreamout =clientSocket.getOutputStream();
out.write(("Hi, welcome to my Home,Client:"+ ip).getBytes());

clientSocket.close();
ss.close();
}
}


3). 演示并分析结果

(1). 先启动服务器端,再启动客户端


(2). 分析程序执行过程

[1]. Server端先运行,首先遇到accept()这个阻塞式方法暂停下来,等待外界对服务端进行连接请求SocketclientSocket
=ss.accept();


[2]. Client端后运行,通过自身的OutputStream对象数据发送给服务器端。之后Client的程序自己向下运行至读取服务器端反馈信息的位置:int
len = in.read(buf);。
由于IO的read方法是阻塞式方法,因此客户端也停下来等待服务器端发送来的信息

[3]. 当服务器有数据发送到客户端的时候,此时阻塞式read()方法可以读到数据,阻塞结束,Client端的程序继续运行

3.    阻塞式方法详解

1). 常见的阻塞式方法

总结】学过的阻塞式方法

{1}. IO流中的BufferedReaderreadLine()方法

{2}. IO流中的InputStreamread(byte[])方法

{3}, UDP通信中的接收方receive(Datagrampacket)方法

{4}. TCP通信中的服务器方accept()方法

结论】程序中遇见阻塞式方法的时候,如果满足阻塞式方法的阻塞条件程序的运行就会暂停下来进行等待。一定记住阻塞式方法阻塞的条件。

2). IO中 Reader抽象父类中阻塞式read方法

(1). Reader中阻塞式的read方法



(2). Reader中阻塞式read方法的原型

[1]. public
int
read() throws IOException;

{1}. 功能:读一个单个字符

{2}. 返回值:以整数的形式返回被读到的字符(0~65535)

[2]. public
int
read(char cbuf[])throws IOException;

和. public
int
read(char cbuf[],int off,
int len)throws IOException;

{1}. 功能:将一组字符读到一个数组cbuf[]

{2}. 返回值:返回读到的字符数

注意如果达到了流的末尾,以上三种read方法都会返回-1

(3). read()方法解除阻塞的条件

[1]. read()

一个字符可以被读或者IO错误发生或者输入流达到了末端(标志就是返回-1)出现的时候,原本阻塞的情况就会被解除

[2]. read(char cbuf[])和read(char cbuf[],int off,
int len)

某种输入可用或者IO错误发生或者输入流达到了末端(标志就是返回-1)出现的时候,原本阻塞的情况就会被解除

3). IO中BufferedReader类中阻塞式readLine方法

(1). 方法源码

public String readLine()throws IOException {
        return readLine(false);
}
[1]. 换行符回车符

{1}. line feed:换行符 =====>
'\n'

{2}. carriagereturn:回车符 =====>'\r'

[2]. 行结束符

换行符回车符或者回车符后面紧随换行符三种情况组成的符号任一都是一种行结束符

[3]. 何谓一行文本

一行文本被认为是换行符 ('\n')或者回车符
(
'\r')或者回车符后面跟上换行符 ("\r\n")结尾字符序列

[4]. 方法功能:可以读取一行文本

[3]. 方法返回值

{1}. 返回仅仅包含该行文本内容但是不包含任何一种行结束符字符串

{2}. 由于readLine方法调用了read方法,所以当流达到了末尾的时候,read方法返回了-1,这个时候由于readLine方法返回值的类型引用类型,所以readLine方法返回值从-1映射成了null

结论当达到了流的结尾的时候,readLine方法返回-1。

(2). readLine()方法解除阻塞的条件

[1]. 【注意】由于readLine方法调用了fill方法fill方法又调用了Reader的read方法,因此BufferedReader的readLine方法也同样是阻塞式的

[2]. read方法解除阻塞的条件

某种输入可用或者IO错误发生或者输入流达到了末端(标志就是返回-1)出现的时候,原本阻塞的情况就会被解除

[3]. readLine方法解除阻塞的条件

某种输入行可用或者IO错误发生或者输入流达到了末端(标志就是返回null)出现的时候,原本阻塞的情况就会被解除

注意】readLine能返回数据(也就是阻塞解除)的情况之一必须是有输入数据(换行符 ('\n')或者回车符
(
'\r')或者回车符后面跟上换行符 ("\r\n")结尾字符序列)才能算为“某种输入行可用”。如果读到的字符序列中没有上述的行结束符结尾readLine方法就会一直在那等着行结束符的到来,也就会一直阻塞下去
(3). IO流中Reader类中阻塞方法解除阻塞的条件总结

常用到的到的解除阻塞情况条件

{1}. 可以读到字符或者字符数组(也叫输入可用)

{2}. 输入流达到了末端 (标志是方法返回-1或者null)

4). UDP通信中的接收方的receive(Datagrampacket)方法

(1). 方法原型

public
void
receive(DatagramPacketp) throws IOException;

(2). receive()方法解除阻塞的条件

直到UDP的接收端的DatagramSocket接收到了数据报包,receive方法才会解除阻塞,方法才会继续执行。

5). TCP通信中的服务器的accept( )方法

(1). 方法原型

public Socket accept()
throws
IOException;

(2). receive()方法解除阻塞的条件

这个方法会一直阻塞直到有来自客户端的Socket这个ServerSocket之间的连接被创建。
结论】程序中遇见阻塞式方法的时候,如果满足阻塞式方法的阻塞条件程序的运行就会暂停下来进行等待。一定记住阻塞式方法阻塞的条件。

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------
 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐