Android网络编程

   第二章 android基本网络技术
1.   计算机网络介绍
    计算机网络体系的通信协议分成: 物理层,数据链接层,网络层,传输层,会话层,表示层,应用层。
      其中低4层完成数据传输服务,上3层面向用户。对于每一层,至少制定2项标准:服务定义和协议规范。前者给出了该层所提供的服务的准确定义,后者详细描述了该协议的动作和各种有关规程,以保证服务的提供。
       应用层:开放系统互联的最高层。应用层为操作系统或网络应用程序提供访问网络服务的接口。
       表示层:为上层用户提供共同的数据或信息的语法表示变换。为了让采用不同编码方法的计算机在通信中能相互理解数据的内容,可以采用抽象的标准方法来定义数据结构,并采用标准的编码表示。表示层管理这些抽象的数据结构,并将计算机内部的表示形式转换成网络通信中采用的标准表示形式。数据压缩和加密也是表示层可提供的表示变换功能。
       会话层:主要功能是组织和同步不同主机上各种进程间的通信(称为对话),负责在两个会话层实体之间进行连接的建立和拆除。会话层还提供在数据流中插入同步同步点的机制,使得数据传输因网络故障而中断后,可以不必从头开始而是仅重传一个同步点以后的数据。
       传输层:负责数据传送的最高层次。传输层完成同处于资源子网中的两个主机间的连接和数据传输,也称为端到端的数据传输。
       网络层:主要是选择合适的路由,是网络层的数据传输单元——分组能够正确无误地按照地址找到目的站。
       数据链接层:负责在两个相邻的节点之间的线路上无差错的传送以帧为单位的数据,每一帧包含一定的数据和必要的控制信息,在数据的接收到数据出错时要通知发送方重发,知道这一帧无误地到达接收节点。
       物理层:定义了为建立,维护和拆除物理链路所需的机械的,电气的,功能的和规程的特性,其作用是使原始的数据比特流能在物理介质上传输。
2. IP  TCP 和 UDP协议
      由于 OSI/RM模型过于复杂难以实现,显示中广泛应用的是TCP/IP模型。 TCP/IP是一个协议集,网络体系结构和协议规范。
      TCP/IP模型也是分层模型,分为4层,具体对象如下:
           
         TCP/IP层分为四层:
        应用层:应用层是大多数普通与网络相关的程序为了通过网络与其他程序通信所使用的层。在应用层中,数据以应用内部使用的格式进行传送,然后被编码成标准协议的格式。例如万维网使用的HTTP协议,文件传输使用的FTP协议,接收电子邮件使用的POP3和IMAP协议,发送邮件使用的SMTP协议,以及远程登录使用的SSH和Telnet等。所以用户通常是与应用层进行交互。
        传输层:传输层响应来自应用层的服务请求,并向网络层发出服务请求。传输层提供两台主机之间透明的数据传输,通常用于端到端的连接,流量控制或错误恢复。这一层的两个重要协议 TCP(传输控制协议)和UDP(用户数据报协议)协议。
        网络层:提供端到端的数据包交付,换言之,它负责数据包从源发送到目的地,任务包括网络路由,差错控制和IP编址等。这一层包括的重要协议 IP协议, ICMP(控制报文协议)协议,和 IPSec(协议安全)
        网络接口层:是TCP/IP参考模型的最底层,负责通过网络发送和接收IP数据包;允许主机炼乳网络时使用多种现成的与流行的技术,如以太网,帧中继,ATM, X.25, DDN , SDH, WDM等。
        一个应用层应用一般都会使用到两个传输层协议之一:面向连接的TCP传输控制协议和 面向无连接的UDP用户数据报协议。下面分析IP , TCP和UDP协议:
 (1)IP协议
         互联网协议(Internet Protocol)是用于报文交换网络的一种面向数据的协议。IP是在TCP/IP协议中网络层的主要协议,任务是根据源主机和目的主机的地址传送数据。为达到目的,IP定义了寻址方法和数据包的封装结构。第一个架构是主要版本,现在成为IPv4,仍然是最主要的互联网协议,如下:
                   
         对IPv4协议包的结构进行介绍,包含多个数据域,各数据域的含义:
         4位版本:表示目前的协议版本号,数值是4表示版本为4,因现在主要使用的还是IPv4协议
         4位首部长度:头部的长度,单位32位(4字节),数值为5表示IP头部长度为20字节。
         8位服务类型(TOS):这个8个字段由3为的优先权子字段(现已忽略),4为的TOS子字段以及1位的未用字段(现为0)构成。4为的TOS子字段包含最小延时,最大吞吐量,最该可靠性以及最小费用构成,对应位为1时指出上层协议对处理当前数据报所期望的服务质量。如果是0,表示一般服务。
         16为总长度(字节数):总长度字段是指整个IP数据报的长度,以字节为单位。如数值为 00 30,换算成十进制为48字节,48字节表示=20字节的IP头,28字节的TCP头。这个数据包只是传送的控制信息,还没有传送真正的数据,所有目前看到的总长度就是包头的长度。
         16位标识:标识字段唯一标识主机发送的每一份数据包。
         3位标志:该字段用于标记该报文是否分片,后面是否还有分片。
         13为片偏移:指当前分片在原数据报中相对于用户数据字段的偏移量,即在原数据报中的相对位置。
         8位生存时间(TTL):TTL(Time-To-Live)生存时间字段设置了数据报可以经过的最多路由器数目。它指定了数据报的生存时间。TTL的初始值由源主机设置,一旦经过一个处理它的路由器,它的值就减1。可根据TTL值判断服务器是什么系统和经过的路由器。举个例子,TTL的十六进制初始值为80H,换算成十进制是128,Windows操作系统的TTL初始值一般是80H,UNIX操作系统的初始值为FFH.
         8位协议:表示协议类型,6表示传输层是TCP协议。
        16位首部校验和:当收到一份IP数据报后,同样对首部中的每16位进行二进制反码的求和。由于接收方在计算过程中包含了发送方存在首部中的校验和,因此,如果首部在传输过程中没有发生任何差错,那么接收方计算的结果应该为全1。如果结果不为全1,即校验和错误,那么IP就丢弃收到的数据包,但是不生成差错报文,而是由上层发现丢失的数据包并进行重传。
         32为源IP地址和32为目的IP地址:实际这是IPv4中核心的部分。32为IP地址由一个网络ID和一个主机ID组成。原地址是指发送数据的源主机的I票地址,目的地址是指接收数据的目的主机的IP地址。
         选项:长度不定,如果没有选项就表示这个字节的域等于0
         数据:该IPv4协议包负载的数据。
(2)TCP协议
        传输控制协议是一种面向连接,可靠的,基于字节流的传输层通信协议。
        在Internet协议族中,传输层是位于网络层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的,像管道一样的连接,但网络层不提供这样的流机制,其只能提供不靠的包交换,所以传输层就自然出现了。
        应用层向传输层发送用于网间传输的,用8位字节表示的数据流,然后TCP协议把数据流分成适当长度的报文段(通常受该计算机连接的网络数据链路层的最大传送单元MTU的限制)。之后TCP协议把结果包出传送被网络层,由他来通过网络将包传送给接收端实体的传输层。TCP为了保证不发生丢包,就给每一个包一个序号,同时序号也保证了传送到接收端实体的包能按序接收。然后接收端实体为已成功收到的包发送一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包(假设丢失了)将会被重传。TCP协议用一个校验和(Checksum)函数来检验数据是否有错误,在发送和接收时都要计算校验和。
        TCP协议头最少多长度为20字节,其协议包结构及所包含的字段如下:
                           
           各字段的含义如下:
      ‰‰16 位源端口号:源端口号是指发送数据的源主机的端口号,16 位的源端口中包含初   始化通信的端口。源端口和源IP 地址的作用是b标识报文的返回地址。 
      ‰‰16 位目的端口号:目的端口号是指接收数据的目的主机的端口号,16 位的目的端口   域定义传输的目的地。这个端口指明报文接收计算机上的应用程序地址端口。
      ‰32 位序号 :TCP 是面向字节流的,在一个 TCP 连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中  的序号字段值则指的是本报文段所发送的数据的第一个字节的序号。
      ‰32 位确认序号 :是期望收到对方下一个报文段的第一个数据字节的序号,若确认号  为N,则表明到序号N-1 为止的所有数据都已正确收到。
      ‰4 位数据偏移:指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远,整  个字段实际上指明了TCP 报文段的首部长度。
      ‰保留(6 位):为了将来定义新的用途而保留的位,但目前应置为 0。
      ‰URG、ACK、PSH、RST、SYN、FIN:6 位标志域,依次对应为紧急标志、确认标志、  推送标志、复位标志、同步标志、终止标志。
      ‰16 位窗口大小 :指的是发送本报文段的一方的接收窗口,以便告诉对方,从本报文  段首部中的确认号算起,接收方目前允许对方发送的数据量。因为接收方的数据缓 存空间有限,该窗口值可作为接收方让发送方设置其发送窗口的依据。
      ‰16 位校验和 :源机器基于数据内容计算一个数值,目的机器根据所接收到的数据内  容也要计算出一个数值,这个数值要与源机器数值完全一样,从而证明数据的有效  性。检验和字段检验的范围包括首部和数据两部分。这是一个强制性的字段,一定  是由发送端计算和存储,并由接收端进行验证的。
      ‰16位紧急指针:在URG标志为1时其才有效,指出了本报文段中的紧急数据的字节数。
      ‰选项:长度可变,最长可达 40 字节。当没有使用选项时,TCP 首部长度是 20 字节。
      ‰数据:该 TCP 协议包负载的数据。
   上述字段中,6位标识域中各标识的功能如下:
      ‰URG:紧急标志。该位为 1 表示该位有效
      ‰ACK :确认标志。该位被置位时表示确认序号栏有效。大多数情况下该标志位是置  位的。
      ‰PSH :推送标志。该标志位置位时,接收端不将该数据进行队列处理,而是尽可能  快地将数据转由应用处理。在处理Telnet 或rlogin 等交互模式的连接时,该标志位 总是置位的。
      ‰RST:复位标志。该位被置位时表示复位相应的 TCP 连接。
      ‰SYN :同步标志。在连接建立时用来同步序号。当 SYN=1 时而 ACK=0 时,表明这  是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中是SYN=1 和  ACK=1。即SYN 置位时表示这是一个连接请求或者连接接受报文。
      ‰FIN:结束标志,用来释放一个连接
(3)UDP协议
   用户数据报协议(UDP)是TCP/IP模型中一种面向无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP协议基本上市IP协议与上层协议的接口。UDP协议适用于端口分别运行在同一台设备上的多个应用程序中。
   与TCP不同,UDP并不提供对IP协议的可靠机制,流控制以及错误恢复功能等,在数据传输之前不需要建立连接。由于UDP比较简单,UDP头包含很少的字节,所以比TCP负载消耗少。
   UDP使用与不需要TCP可靠机制的情形,比如,当高层协议或应用程序提供错误和刘控制功能的时候。UDP服务于很多知名应用层协议,包括网络文件系统(NFS),简单网络管理协议(SNMP),域名系统(DNS)以及简单文件传输系统(TFTP)。
   UDP数据报格式包含的字段如下:
     ‰源端口 :16 位。源端口是可选   字段。当使用时,它表示发送  程序的端口,同时它还被认为  是没有其他信息的情况下需要  被寻址的答复端口。如果不使  用,设置其值为0。
     ‰目的端口:16 位。目标端口在  特殊互联网目标地址的情况下具有意义。
     ‰长度:16 位。UDP 用户数据报的总长度。
     ‰校验和:16 位。用于校验 UDP 数据报的 UDP 首部和 UDP 数据。
     ‰数据:包含上层数据信息。
3. 在android中使用TCP, UDP协议
       上面介绍了TDP和UDP的报文结构,每段报文里除了数据本身,还包含了包的目的地址和端口,包的源地址和端口以及其他各种附加的校验信息。这些包的长度是有限的,传输的时候需要将其分解为多个包,在到达传输的目的地址后再组合还原。若包有丢失或破坏需要重传时,则乱序发送的包在达到使需要重新排序。处理这一过程是非常麻烦的,这一过程,人们通过Socket对网络纠错,包大小,包重传等进行了封装。
(1)Socket基础
         Socket称为套接字,一台服务器可能会提供很多服务,每个服务对应一个Socket(每个Socket就是一个插座,客户若是需要哪种服务,就将插座插到相应的插座上面),而客户的“插头”也是一个Socket。Socket是应用层与TCP/IP协议族通信的中间软件抽象层,他是一组接口,Socket把复杂的TCP/IP协议族隐藏在Socket端口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。Socket用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过套接字向网络发送请求或者应答网络请求。
         套接字的基本操作包括:
                连接远程机器,发送数据,接收数据,关闭连接,绑定端口,监听到达数据,在绑定端口上接收来自远程机器的连接。
         服务器要和客户端通信,两者都要实例化一个Socket。服务端和客户端的Socket是不一样的,客户端可以实现连接远程机器,发送数据,接收数据,关闭连接等,服务器还需要实现绑定端口,监听到达的数据,接收来自远程机器的连接。Android在包 java.net 里提供了两个类: ServerSocket 和 Socket, 前者用于实例化服务器的Socket,后者用于实例化客户端的Socket。在来连接成功后,应用程序两段都会产生一个Socket的实力,操作这个实例,完成客户端到服务器所需的会话。
        下面分析一些重要的Socket编程接口。
         构造一个客户端Socket,常用的构造函数如下:
                   ‰‰Socket():创建一个新的未连接的 Socket。
                   ‰‰Socket(Proxy proxy):使用指定的代理类型创建一个新的未连接的 Socket。
                   ‰‰Socket(String dstName,int dstPort) :使用指定的目标服务器的 IP 地址和目标服务器  的端口号,创建一个新的Socket。 
                   ‰‰Socket(String dstName,int dstPort,InetAddress localAddress,int localPort) :使用指定  的目标主机、目标端口、本地地址和本地端口,创建一个新的Socket。 
                   ‰‰Socket(InetAddress dstAddress,int dstPort) :使用指定的本地地址和本地端口,创建  一个新的Socket。 
                   ‰‰Socket(InetAddress dstAddress,int dstPort,InetAddress localAddress,int localPort) :使  用指定的目标主机、目标端口、本地地址和本地端口,创建一个新的Socket。
          其中,proxy是代理服务器地址,dstAddress 为目标服务器IP 地址,dstPort 为目标服  务器的端口号(因为服务器的每种服务都会绑定在一个端口上面),dstName 为目标服务器 的主机名。Socket构造函数举例如下:
                            Socket  client  = new Socket("192.168.1.1",  2012);//目标服务器的IP地址和端口号 
                            Socket  sock = new Socket( new Proxy( Proxy.Type.SOCKS,  new  InetSocketAddress( "test.domain.org", 2100 ) ) );//实例化一个proxy,以该proxy为参数,创建一个新的Socket.
             
              构造一个服务器端的ServerSocket的方法:
                        ‰ServerSocket():构造一个新的未绑定的 ServerSocket。
                        ‰‰ServerSocket(int port) :构造一个新的 ServerSocket 实例并绑定到指定端口。如果   port 参数为0,端口将由操作系统自动分,此时进入队列的数目将被设置为50。 
                        ‰‰ServerSocket(int port,int backlog) :构造一个新的 ServerSocket 实例并绑定到指定端   口,并且指定进入队列的数目。如果port 参数为0,端口将由操作系统自动分配。 
                       ‰‰ServerSocket(int port,int backlog,InetAddress localAddress) :构造一个新的 ServerSocket   实例并绑定到指定端口和指定的地址。如果localAddress 参数为null,则可以使用任 意地址,如果port 参数为0,端口将由操作系统自动分配。
            创建实例:
                       ServerSocket  socketserver = new ServerSocket( 2012 );//2012表示服务器要监听的端口号。
            构造完ServerSocket 之后,需要调用ServerSocket.accept() 方法来等待客户端的请求(因为Socket都是绑定在端口上面的,所以知道是哪个客户端请求的)。accept() 方法就会返回请求这个服务的客户端的 Socket 实例,然后通过返回的这个Socket实例的方法,操作传输过来的信息。当Socket对象操作完毕之后,使用close()方法将其关闭。
                
          Socket一般有两种类型: TCP套接字和UDP套接字
          TCP和UDP在传输过程中的具体实现不同。两者都接收传输协议数据包并将其内容向前传送到应用层。TCP把消息分解成数据包(数据报 datagrams)并在接收端以正确的顺序把他们重新装配起来,TCP还处理对遗失数据包的重传请求,位于上层的应用层要处理的事情就少多了。UDP不提供装配和重传请求这些功能,它只是向前传送消息包。位于上层的应用层必须确保消息是完整的,并且以正确的顺序装配。
   使用TCP通信
          TCP建立连接之后,通信双方都同时可以进行数据的传输;在保证可靠性上,采用超时重传和捎带确认机制;在流量控制上,采用滑动窗口协议,在协议中规定,对于串口内未经确认的分组需要重传;在拥塞控制上,采用慢启动算法。TCP通信的原理图如下:
                       
           TCP服务端工作的主要步骤如下:
           -> 调用 ServerSocket(int  port)创建一个 ServerSocket,并绑定到指定端口上。
           -> 调用accept(),监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字。
           -> 调用 Socket类的 getOutputStream()和 getInputStream() 获取输出和输入流,开始网络数据的发送和接收。
           -> 关闭套接字。
           实例代码如下:
               ****************************************************************************
ServerSocket serverSocket = null;
try{
 serverSocket = new ServerSocket(TCP_SERVER_PROT);//TCP_SERVER_PROT指定绑定端口,为int类型
  Socket socket = serverSocket.accept();
 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));//获取输入流
 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//获取输出流
 String incomingMsg = in.readLine() + System.getProperty("line.separator");//读取接收信息,转换为字符串
 String outgoingMsg = "goodby from prot" + TCP_SERVER_PORT + System.getProperty("line.separator");//将发送字符串写入到上面定义的BufferedWriter中
 out.write(outgoingMsg);
 out.flush();//刷新,发送
 socket.close();
}cach(InterruptedIOException e){//超时错误
 e.printStackTrace();
}catch(IOException e){
    e.printStackTrace();
}finally{
 //判断是否初始化serverSocket对象,如果初始化则关闭serverSocket
 if(serverSocket != null){
  try{
    serverSocket.close();
  }catch(IOException e){
            e.printStackTrace();
  }
 }
}
                ****************************************************************************
           TCP客户端工作的主要步骤如下:
           -> 调用 Socket()创建一个流套接字,并连接到服务器端
           -> 调用调用Socket 类的getOutputStream() 和getInputStream() 方法获取输出和输入  流,开始网络数据的发送和接收。
           -> 关闭通信套接字。
           TCP客户端代码如下:
                 ****************************************************************************
try{
  Socket socket = new Socket("localhost", TCP_SERVER_PORT);
 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
 String outMsg = "TCP connecting to " + TCP_SERVER_PORT + System.getProperty("line.separator");
 out.write(outMsg);
 out.flush();
 String inMsg = in.readLine() + System.getProperty("line.separaotr");
 socket.close();
}catch(UnknownHostException e){
    e.printStackTrace();
}catch(IOException e){
    e.printStackTrace();
}
               
         客户端和服务端都需要处理UnknownHostException (处理网络异常)和IOException异常处理
         同时在android配置文件中需要添加:
                    <uses-permission android:name="android.permission.INTERNET" />
      使用UDP通信
         UDP有不提供数据报分组,组装和不能对数据包排序的特点,当报文发送之后,是无法得知其是否安全完整到达。UDP用来支持那些需要在计算机之间传输数据的网络应用,包括网络视频会议系统在内的众多的客户端/服务器模式的网络应用都需要使用UDP。UDP协议的主要作用是将网络数据流量压缩成数据报的形式。一个典型的数据报就是一个二进制数据的传输单位。
                    
           UDP服务端工作的主要步骤:
          -> 调用DatagramSocket(int port) 创建一个数据报套接字,并绑定到指定端口上。
          -> 调用DatagramPacket(byte[]buf,int length),建立一个字节数组以接收UDP 包。
          -> 调用DatagramSocket 类的receive(),接受UDP 包。
          -> 关闭数据报套接字
          实例如下:
             ****************************************************************************
byte[] lMsg = new byte[MAX_UDP_DATAGRAM_LEN];//接收的字节大小,客户端发送的数据不能超过MAX_UDP_DATAGRAM_LEN
DatagramPacket dp = new DatagramPacket(lMsg, lMsg.length);//实例化该类
DatagramSocket ds = null;
try{
  ds = new DatagramSocket(UDP_SERVER_PORT);
 ds.receive(dp);
}catch(SocketException e){
 e.printStackTrace();
}catch(IOException e){
    e.printStackTrace();
}finally{
 if(ds != null){
  ds.close();
 }
}
            ****************************************************************************
         UDP客户端主要做的工作:
        -> 调用DatagramSocket() 创建一个数据包套接字。
        -> 调用DatagramPacket(byte[]buf,int offset,int length,InetAddress address,int port),   建立要发送的UDP 包。
        -> 调用DatagramSocket 类的send() 发送UDP 包。
        -> 关闭数据报套接字。
         具体事例:
              ****************************************************************************
String udpMsg = "hello world from UPD client" + UDP_SERVER_PORT;
DatagramSocket ds = null;
try{
  ds = new DatagramSocket();
 InetAddress serverAddr = IneAddress.getByName("127.0.0.1");//初始化地址对象
 DatagramPacket dp = new DatagramPacket(udpMsg.getBytes(), udpMsg,length(), serverAddr, UDP_SERVER_PORT);
 ds.send(dp);
}catch(SocketException e){
 e.printStackTrace();
}catch(UnknownHostException e){
    e.printStackTrace();
}catch(IOException e){
 e.printStackTrace();
}catch(Exception e){
 e.printStackTrace();
}finally{
 if(ds != null){
   ds.close();
 }
}
            ****************************************************************************
(4)Socket实例
       Socket聊天为例,实现从服务端到客户端的聊天功能。
       服务器的任务如下:ChatServer类负责开启Server端服务;ReceiveMsg服务接收消息;SendMsg负责发送消息;Server端响应请求,向Client端返回数据,其主要代码如下:
 ****************************************************************************
import java.net.*;
import java.io.*;
//创建一个客户端
class ChatServer extends Thread
{
 public  ChatServer() throws IOException{
  CreateSocket();//创建Socket服务器
 }
 public void run(){
  Socket client;
  String txt;//定义接收的文本
  try{
   while(true){//始终监听
    //开启线程,实时监听socket端口
    //获取应答消息
    client = ResposeSocket();
    while(true){
     txt = ReceiveMsg(client);//接收客户端的消息
     System.out.println("client send message: " +txt);
     SendMsg(client, txt);
     if(true) break;
    }
    CloseSocket(client);
   }
  }catch(IOException e){
   e.printStackTrace();
  }
 }

    private ServerSocket server = null;
 private static final int PORT = 5000;
 private BufferedWriter writer;
 private BufferedReader reader;

 private void CreateSocket()throws IOException{
  server = new ServerSocket(PORT, 100);
 }
 private Socket ResposeSocket()throws IOException{
  Socket client = server.accept();
  return client;
 }
 private void CloseSocket(Socket socket)throws IOException{
  reader.close();
  writer.close();
  socket.close();
 }
 private void SendMsg(Socket socket, String Msg)throws IOException{
        writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
  writer.write(Msg + "\n");
  writer.flush();
 }
 private String ReceiveMsg(Socket socket)throws IOException{
  reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  String txt = reader.readLine();
  return txt;
 }
}
class ServerDemo
{
 public static void main(String[] args)throws IOException{
   ChatServer chatserver = new ChatServer();
   if(chatserver != null){
    chatserver.start();
   }
 }
}
 ****************************************************************************    
       客户端发起连接请求,并向服务器端发送数据;客户端接收服务器的数 据,其主要代码如下:
  ****************************************************************************  
import java.net.*;
import java.io.*;
class ClientDemo
{
 public static void main(String[] args) throws IOException
 {
   Socket socket = RequestSocket("192.168.78.1", 5000);
   SendMsg(socket, "hello yinazh");
   System.out.println("Receive data:" + ReceiveMsg(socket));
 }
 private static Socket RequestSocket(String host, int port)throws UnknownHostException, IOException{
  Socket socket = new Socket(host, port);
  return socket;
 }
 private static void SendMsg(Socket socket, String msg)throws IOException{
  BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
  writer.write(msg.replace("\n", " ") + "\n");
  writer.flush();
 }
 private static String ReceiveMsg(Socket socket)throws IOException{
  BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  String Msg = reader.readLine();
  return Msg;
 }
}
 **************************************************************************** 
(5)FTP客户端
        文件传输协议(FTP, File Transfer Protocol)是用于在网络上进行文件传输的一套标准协议。它属于网络传输协议的应用层。
        FTP是一个8位的客户端-服务端协议,能操作任何类型的文件。FTP服务一般运行在20和21两个端口。端口20用于在客户端和服务端之间传输数据流,而端口21用于传输控制流,并且是命令通向FTP服务器的进口。当数据通过数据流传输时,控制流处于空闲状态。运行FTP服务的许多站点都开放匿名服务,在这种设置下,用户不需要账号就可登陆服务器,默认匿名用户的用户名是 anonymous,这个账号不需要密码;不开放匿名服务的则要求输入用户名和密码。
        Android中可以使用第三方的库莱操作FTP,这里使用Apache的包。
        步骤1: 在项目引入包 commons-net-3,2.jar 之后,导入需要其中的FTPClient类,代码如下;
                 import  org.apache.commons.net.ftp.FTPClient;
        步骤2: 初始化 FTPClient,代码如下:
                 mFtp = new FTPClient();
        步骤3:设置登录地址和端口号,代码如下:
                 mFtp.connect( FTP_URL, 21 );
        步骤4:设置登录用户名和密码,代码如下;
                 mFtp.login( Name, Password ) ;
        步骤5:设置文件类型和采用被动传输方式,代码如下:
                 mFtp.setFileType( FTP.BINARY_FILE_TYPE );
                 mFtp.enterLocalPassiveMode();
        步骤6: 传输文件,代码如下:
                 boolean aRtn = mFtp.storeFile( remoteFileName, aInputStream );
                 aInputStream.close();//成功,返回true
        步骤7:关闭连接,代码如下:
                 mFtp.disconnect();
 注意:FTP支持一下两种模式:
            主动模式:FTP客户端向服务器的FTP控制端口(默认是21端口)发送请求,服务器接收连接,建立一条命令链路,当需要传送数据时,客户端在命令链路上用PORT命令通知服务器,服务器从20端口向客户端的该端口发送连接请求,建立一条数据链路来传送数据。在数据链路建立的过程中因为是服务器主动请求的,所以成为主动模式。
            被动模式:FTP客户端向服务器的FTP控制端口发送连接请求,服务器接收连接,建立一条命令链路,当需要传送数据时,服务器在命令链路上用PASV命令通知客户端;客户端向服务器的该端口发送连接请求,建立一条数据链路来传送数据。在数据链路建立的过程中因为是服务器被动等待客户端请求的,所以成为被动模式。
          Android FTP客户端核心代码如下:
  ****************************************************************************  
import org.apache.commons.net.ftp.FTPClient;
FTPClient ftpClient = new FTPClient();
try{
    ftpClient.connect(InetAddress.getByName(SERVER));//连接指定的FTP服务器
    ftpClient.login(USERNAME, PASSWORD);//登陆
 //检测返回的字符串里面是否包含250,250相应代码表示行为完成
 if(ftpClient.getReplyString().contains("250")){
  ftpClient.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
  BufferedInputStream buffIn = new BufferedInputStream(new FileInputStream(FULL_PATH_TO_LOCAL_FILE));//将文件加载到缓冲区中
   ftpClient.enterLocalPassiveMode();//设置客户端PASV模式(客户端主动连接服务器端;端口20)
  boolean result = ftpClient.storeFile(localAsset.getFileName(), progressInput);//存储文件,返回是否成功
  buffIn.close();
   ftpClient.logout();/ /等处
  ftpClient.disconnect();
 }
}catch(SocketException e){
 e.printStackTrace();
}catch(UnknownHostException e){
 e.printStackTrace();
}catch(IOException e){
 e.printStackTrace();
}
 **************************************************************************** 
(6)Telnet客户端
         Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机上的工作能力。在终端使用者的计算机上使用Telnet程序,用它连接服务器。终端使用者可以在Telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。通过Telnet在本地就能控制服务器。要开始一个Telnet会话,必须输入用户名和密码来登陆服务器。Telnet是常用的远程控制Web服务其的方法。
         Android中科使用第三方库来操作Telnet,这里使用Apache的包。具体步骤:
         -> 导包,              import  org.apache.commons.net.telnet.TelnetClient;
         -> 初始化TelnetClient:    TelnetClient tc = new TelnetClient();
         -> 打开连接:       tc.connect( remoteip,  remoteport );
         -> 读写数据:       tc.getInputStream()             tc.getOutputStream();
         -> 断开Telnet连接:    tc.disconnect();
         Android Telnet客户端的核心代码:
  ****************************************************************************  
import org.apache.commons.net.telnet.TelnetClient;
TelnetClient telnet = new TelnetClient();
try{
 telnet.connect(remoteip, remoteport);
}catch(IOException e){
 e.printStackTrace();
 System.exit(1);
}
IOUtil.readWrite(telnet.getInputStream(), telnet.getOutputStream(), System.in, System.out);
try{
 telnet.disconnect();
}catch(IOException e){
    e.printStackTrace();
}
//其中调用的IOUtil类封装了一些读写操作
public final class IOUtil
{
 public static final void readWrite(final InputStream remoteInput,
  final OutputStream remoteOutput,
  final InputStream localInput,
  final OutputStream localOutput){
  Thread reader, writer;
  read = new Thread(){
   public void run(){
    int ch;
    try{
     //判断没有被中断的时候    不是结束标识
     while(!interrupted() && (ch = localInput.read())!= -1){
      remoteOutput.write(ch);//写字节到远程输入里面
      remoteOutput.flush();
     }
    }catch(IOException e){
     e.printStackTrace();
    }
   }
  };
  writer = new Thread(){
   public void run(){
    try{
     Util.copyStream(remoteInput, localOutput);
    }catch(IOException e){
     e.printStackTrace();
     System.exit(1);
    }
   }
  };
  writer.setPriority(Thread.currentThread().getPriority() +1);
  writer.start();
  reader.setDaemon(true);//设置为后台运行
  reader.start();
  try{
   writer.join();//使得writer线程完成run()方法后,在执行join()方法后的代码
   reader.interrupt();//中断reader线程
  }catch(InterruptedException e){
   e.printStackTrace();
  }
 }
}
 **************************************************************************** 

     第三章   android基本web技术和编程实践
       本章主要介绍android的web编程,包括android中的HTTP编程,以及使用android处理JSON,SOAP,HTML等。
一. HTTP协议
       HTTP协议是互联网上应用最为广泛的一种网络协议标准,所有的WWW文件都必须遵守这个标准。
3.1 .  HTTP讲解
         其是一种适用于分布式超媒体信息系统的应用层协议。特点:
    -> 支持 C/S模式
    -> 简单快速。客户向服务器发送请求服务时,只需发送请求方法和路径。请求方法常有 GET,  HEAD,  POST。每种方法规定了客户与服务器联系的不同类型。由于HTTP协议简单,服务器的程序规模较小,因此其通信速度很快。
    -> 灵活。HTTP允许传输任意类型的数据对象。正在传输的类型由 Content-Type加以标记
    -> 无连接。限制每次连接只处理一个请求。服务器处理完客户的请求,并受到客户的应答后,即断开连接。
    -> 无状态。HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
     绝大多数的Web开发都是构建在HTTP协议之上的Web应用。要想了解web开发,先了解 HTTP 的URL,其一般形式如下:
                    http:// host[":"port][abs_path] 
      http表示要通过HTTP协议来定位网络资源; host表示合法的 Internet 主机域名或 IP 地址;port 指定一个端口号,为空则使用默认端口80;abs_path 指定资源的URL(通用资源标识符,只web上任意的可用资源)。
     HTTP报文是面向文本的,报文中的每一个字段都使一些 ASCII 码串,各个字段的长度是不确定的。
     HTTP有两类报文: 请求报文和响应报文
   1.  HTTP请求报文
      一个HTTP请求报文由请求行,请求报头,空行和请求数据4部分组成,请求报文的一般格式如下:
               
        (1)请求行
          请求行由请求方法字段,URI字段和HTTP协议版本字段组成,他们之间用空格分隔。格式如下:
                    Method  Request-URI  HTTP-Version  CRLF
               例如: GET /form.html HTTP/1.1 (CRLF)
          其中CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)
          请求方法有多种,各种方法的解释如下:
                   
                    
          (2)请求报头
          (3)空行
                 最后一个请求头是一个空行,发送回车符和换行符,通知服务器一下不再有请求头。
          (4)请求数据
                 请求数据不在GET方法中使用,而是在POST方法中使用。POST方法适用于需要客户填写表单的场合。与请求数据相关的,最常食用的请求头饰Content-Type 和Content-Length
                 在接受和解释请求消息后,服务器会返回一个HTTP响应消息。
   2.  HTTP响应报文
            HTTP响应报文也是由4部分组成的,分别是:状态行,消息报文,空行,响应正文,如图所示:
                      
          (1)状态行
                格式如下:            HTTP-Version Status-Code Reason-Phrase CRLF
                         例如:   HTTP/1.1 200 OK (CRLF)
                其中 Status-Code表示服务器发回的相应状态代码; Reason-Phrase表示状态代码的文本描述
                状态代码由3位数字组成,第一个数字定义了响应的类别,有5种可能取值,如下:
                          
               状态代码具体种类很多,常见的如下:
                          
           (2)响应报头
           (3)空行       这行是空的
           (4)响应正文     相应正文就是服务器返回的资源的内容
  3.  HTTP消息报头
          HTTP消息由客户端到服务器的请求和服务器到客户端的响应组成。请求消息和响应消息都是由 开始行(对于请求消息,开始行就是请求行;对于相应消息,开始行就是状态行), 消息报头(可选),空行(只有CRLF的行),消息正文(可选)4部分组成。
         其中消息报头包括普通报头,请求报头,响应报头,实体报头。消息报头由“头部字段名/值”对组成,每行一对,头部字段名和值用“:”分隔,即如下形式:        头部字段名 + “:”+ 空格 +值
   其中消息报头字段名是大小写无关的。报头描述了客户端或服务器的属性,被传输的资源以及应该实现的连接。
  4种不同类型的消息报头分述如下:
    ‰普通报头:即可用于请求,也可用于响应,不用于被传输的实体,只用于传输消息,   是作为一个整体而不是特定资源与事务相关联。比如,Date 普通报头表示消息产生 的日期和时间;Connection 普通报头允许发送指定连接的选项,例如指定连接是连 续,或者指定close 选项,通知服务器,在响应完成后,关闭连接。 
    ‰请求报头 :允许客户端传递关于自身的信息和希望的响应形式。请求报头通知服务   器有关客户端请求的信息,典型的请求报头有如下几种。 
       ��User-Agent:包含产生请求的操作系统、浏览器类型等信息。
       ��Accept:客户端可识别的内容类型列表,用于指定客户端接受哪些类型的信息。
       ��Host:请求的主机名,允许多个域名同处一个 IP 地址,即虚拟主机。
    ‰响应报头:服务器用于传递自身信息的响应。典型的响应报头有如下两种。
       ��Location :用于重定向接收者到一个新的位置。Location 响应报头常用在更换域   名的时候。 
       ��Server :包含了服务器用来处理请求的系统信息,与 User-Agent 请求报头是相对   应的。
    ‰实体报头 :定义被传送资源的信息。既可用于请求,也可用于响应。请求和响应消   息都可以传送一个实体。典型的实体报头如下。 
       ��Content-Encoding :被用作媒体类型的修饰符,它的值指示了已经被应用到实体   正文的附加内容的编码。因而要获得Content-Type 报头中所引用的媒体类型,必  须采用相应的解码机制。 
       ��Content-Language :描述了资源所用的自然语言。没有设置该选项则认为实体内   容将提供给所有的语言阅读。 
       ��Content-Length:用于指明实体正文的长度,以字节方式存储的十进制数字来表示。
       ��Last-Modified:用于指示资源的最后修改日期和时间。
4. 实例:基于HTTP协议的文件上传
         HTTP协议文件上传的功能是通过RFC1867规范来描述的,Chrome, IE,  Mozila 和 Opera等浏览器都支持此功能。此例从搭建服务器开始,分析了文件上传及上传的过程。
        步骤1:建立PHPserver 服务器
        步骤2:分析HTTP上传过程——使用fiddler2分析使用HTTP协议文件上传的过程,找到上传文件需要的标准数据格式
        步骤3: 编写android代码实现文件上传,具体代码如下:
*****************************************************************
public static String post(String actionUri, String FileName) throws IOException{
 //产生随机分隔内容
 String BUNDARY = java.util.UUID.randomUUID().toString();
 String PREFIX = “--”, LINEND = "\r\n";
 String MULTIPART_FROM_DATA = "multipart/form-data";
 String CHARSET = "UTF-8";
 //定义URL实例
 URL uri = new URL(actionUri);
 //定义HttpURLConnection实例,打开连接
 HttpURLConnection conn = (HttpURLConnection)uri.openConnection();
 conn.setReadTimeout(5*1000);//设置从主机读取数据超时
 conn.setDoInput(true);//设置允许输入
    conn.setDoOutput(true);//设置允许输出
 conn.setUseCatches(false);//设置不允许使用缓存
 conn.setRequestMethod("POST");//设置为POST发送方法
 conn.setRequestProperty("connection", "keep-alive");//设置维持长连接
 conn.setRequestProperty("Charsert", "UTL-8");//设置文件字符集为UTL-8
 conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY);//设置文件类型
 //创建一个新的数据输出流,将数据写入指定基础输出流
 DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
    if(FileName != ""){
  StringBuilder sb1 = new StringBuilder();
  sb1.append(PREFIX);
  sb1.append(BOUNDARY);
  sb1.append(LINEND);
  sb1.append("Content-Disposition: form-data;name=\"file1\"; filename=\"\" +FileName + \“\”"+ LINEND);
  sb1.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINEND);
  sb1.append(LINEND);
        outStream.write(sb1.toString().getBytes());
  InputStream is = new FileInputStream(FileName);//将文件读取到输入流中
  byte[] buffer = new byte[1024];
  int len = 0;
  while((len = is.read(buffer)) != -1){
   outStream.write(buffer, 0, len);
  }
  is.close();
  outStream.write(LINEND.getBytes());//添加换行标志
 }
    byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();//请求结束标识
 outStream.write(end_data);
 outStream.flush();
 int res = conn.getResponseCode();
 InputStream in = null;//得到响应码
 if(res == 200){
  in = conn.getInputStream();
  int ch;
  StringBuilder sb2 = new StringBuilder();
  while((ch = in.read())!= -1){
   sb2.append((char)ch);
  }
 }
 return in == null ? null : in.toString();//若数据不为空,则以字符串的方式返回数据
}
*****************************************************************

二. Android中的HTTP编程
1.  HttpClient和URLConnection
       越来越多的应用程序直接通过HTTP协议来访问网络资源。虽然在android的 java.net 包中已经提供了访问 HTTP协议的基本功能,但android原声提供的功能不够丰富和灵活。 HttpClient 是 Apache Jakarta Common下的子项目,用来提供高效的,最新的,功能丰富的支持HTTP协议的客户端变成工具包,并支持HTTP协议的最新的版本和建议。
       普通网页上提供的信息访问,我们一般可以取得,当时有些特殊的服务,考虑到一些授权的问题,就不是通过一个URL可以访问的了,就必须注册登陆后才可是哦那个服务的页面,这是就涉及到了COOKIE的处理问题。这些问题,HttpClient可以轻松解决,HttpClient就是专门设计用来简化HTTP客户端与服务器间各种通信编程的。
      URL代表统一资源定位符,其指向互联网资源的指针。URLConnection则代表了应用程序和URL之间的通信链接,通过 URLConnection类的实例可以读取和写入此URL应用的资源。
2. Post和Get在HttpClient的使用
      HttpClient提供的主要的功能如下:
         》实现了所有HTTP的方法(GET,  POST, PUT , HEAD等)
         》支持自动转向
         》支持HTTPS协议
         》支持代理服务器
      HTTP请求方法中最常用的GET方法和POST方法。
(1)GET方法
        GET方法要求服务器将URL定位的资源放在响应报文的数据部分,回送客户端。使用GET方法时,请求参数和对应的值附加在URL后面,利用一个问好(“?”)代表URL的结尾和请求参数的开始。
******************************************************************
//通过GET方法获取页面信息
//参数对应页面的URL
public static InputStream getInputStreamFromUrl(String url){
 InputStream content = null;
 try{
  HttpClient httpclient = new DefaultHttpClient();//获取默认的HttpClient实例
  //连接服务器  创建HttpGet实例
  HttpResponse response = httpclient.execute(new HttpGet(url));
  //获取数据内容
  content = response.getEntity().getContent();
 }catch(Exception e){
 }
 return content;
}
**********************************************************************
        此时的GET方法是以 InputStream的形式返回页面的信息,很多情况下需要以StringBuilder,   String 等字符串的形式。下面的方法是把InputStream格式转换为 StringBuilder 和String 格式.
**********************************************************************
private StringBuilder inputStreamToStringBuilder(InputStream is){
 String line = "";
 StringBuilder total = new StringBuilder();
 BufferedReader rd = new BufferedReader(new InputStreamReader(is));
 while((line = rd.readLine()) != null){
  total.append(line);
 }
 return total;
}
private String inputStreamToString(InputStream is){
 String s = "";
 String line = "";
 BufferedReader rd = new BufferedReader(new InputStreamReader(is));
 while((line = rd.readLine()) != null){
  s += line;
 }
 return s;
}
**********************************************************************
(2)POST方法
        POST方法要求被请求服务器接收附在请求后面的数据,常用于提交表单。当客户端给服务器提供信息较多时可以使用POST方法。POST方法将请求参数封装在HTTP请求数据中,以名称值得形式出现,可以传输大量数据。
**********************************************************************
public void postData(){
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(" http://www.google.com");
try{
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);//添加数据
        nameValuePairs.add(new BasicNameValuePair("stringdata", "mystring"));
httppost.setEntity(new UriEncodedFormEntity(nameVaulePairs, "UTF-8"));//使用utf-8格式对数据进行编码
HttpResponse response = httpclient.execute(httppost);
}catch(ClientProtocolException e){
}catch(IOException e){
}
}
**********************************************************************
          使用HttpClient需要以下6个步骤:
》创建HttpClient的实例
》创建某种连接方式的实例,对于get方法是GetMethod,对于post方法是PostMethod
》调用步骤1中创建好的实例的execute方法来执行步骤2中创建好的method实例 
》读取response
》释放连接
》对得到的内容进行处理
3.  实战案例:使用HttpClient 和 URLConnection 访问维基百科
         本例使用URLConnection对象和HttpClient组件访问维基百科。了解维基百科API的构成。
         维基百科是一个内容开放的,多语言的百科全书写作计划。其内容除了浏览外,还给出了其自身的API访问接口。
         本案例使用的API的格式如下:
         其中 action=opensearch表示使用OpenSearch协议来访问该API
         search=Android 表示搜索的关键词为Android; 前面的&为连接符号。
**********************************************************************
注意: URL中的一些字符有特殊含义,基本编码规则如下:
       空格换成加号(+); 正斜杠(/)分隔目录和子目录;问号(?)分隔URL和查询;百分号(%)指定特殊字符;#号指定书签;&号分隔参数,有时也作为连接符号。
**********************************************************************
         维基百科的API访问接口中常用的参数及含义如下;
                  
(1)使用URLConnection 访问维基百科
          主要代码如下:
**********************************************************************
String wikiSearchURL = " http://zh.wikipedia.org/w/api.php?action=opensearch&search=Android";
try{
URL url = new URL(wikiSearchURL);
//创建HttpURLConnection,并打开连接
HttpURLConnection httpconn = (HttpURLConnection) url.openConnection();
if(httpconn.getResponseCode() == HttpURLConnection.HTTP_OK){
Toast.makeText(getApplicationContext(), "连接维基百科成功!", Toast.LENGTH_SHORT).show();
//创建InputStreamReader ,设置字符编码为utf-8
InputStreamReader isr = new InputStreamReader(httpconn.getInputStream(), "utf-8");
int i;
String content = "";
while((i = isr.read()) != -1){
content += (char)i;
}
isr.close();
showWiki.setText(content);//在一个TextView上显示出来
}
httpconn.disconnect();
}catch(Exception e){
    Toast.makeText(getApplicationContext(), "连接维基百科失败!", Toast.LENGTH_SHORT).show();
    e.printStackTrace();
}
**********************************************************************
(2)使用 HttpClient访问维基百科
         代码如下:
**********************************************************************
String wikiSearchURL = " http://zh.wikipedia.org/w/api.php?action=opensearch&search=Android";
DefaultHttpClient httpclient = new DefaultHttpClient();//创建DefaultHttpClient
HttpGet httpget = new HttpGet(wikiSearchURL);//创建HttpGet
ResponseHandler<string> responseHandler = new BasicResponseHandler();//创建ResponseHandler
try{
    String content = httpclient.execute(httpget, responseHandler);//获取返回的内容
Toast.makeText(getApplicationContext(), "连接维基百科成功!", Toast.LENGTH_SHORT).show();
showWiki.setText(content);
}catch(Exception e){
Toast.makeText(getApplicationContext(), "连接维基百科失败!", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
httpclient.getConnectionManager().shutdown();//关闭连接
**********************************************************************

实例获取百度页面(简单请求)
**********************************************************************
package com.example.httpdemo;

import java.io.IOException;

import android.os.Bundle;
import android.widget.Button;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;
import java.io.*;
import android.util.Log;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;

public class MainActivity extends Activity {

    private Button reButton = null;
    private TextView reText = null;
    private String result = null;
    //服务器的响应内容
    private HttpResponse httpResponse = null;
    //用于从服务器响应内容中获取数据,代表接收到的HTTP消息,服务器端发回的响应数据
    private HttpEntity httpEntity = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        reText = (TextView)findViewById(R.id.reponse_info);
        reButton = (Button)findViewById(R.id.reguestButton);
        reButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                new ThreadDemo().start();
                reText.setText(result);
            }
        });
    }

    class ThreadDemo extends Thread{
        public void run(){
            HttpGet httpGet = new HttpGet(" http://www.baidu.com");
            //生成一个客户端
            HttpClient httpClient = new DefaultHttpClient();
            InputStream inputStream = null;
            try {
                //发送请求
                httpResponse = httpClient.execute(httpGet);
                httpEntity = httpResponse.getEntity();
                inputStream = httpEntity.getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                String line = null;
                while((line = reader.readLine()) != null){
                    result = line;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                try{
                    inputStream.close();
                }catch(Exception e){
                    e.printStackTrace();
                }
            }            
        }
    }
}
**********************************************************************
出现问题,不能将网络连接的过程放在主线程中。
使用post和get发送请求实例:
**********************************************************************
package com.example.httpdemo02;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.NameValuePair;

import android.os.Bundle;
import android.widget.EditText;
import android.widget.Button;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.util.Log;


public class MainActivity extends Activity {

    private EditText name_text = null;
    private EditText age_text = null;
    private Button get_button = null;
    private Button post_button = null;
    private String baseUrl = " http://192.168.1.100:8081/serverside/name";
    //服务器的响应内容
    private HttpResponse httpResponse = null;
    //用于从服务器响应内容中获取数据,代表接收到的HTTP消息,服务器端发回的响应数据
    private HttpEntity httpEntity = null;
    private String result = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        name_text = (EditText)findViewById(R.id.name_text);
        age_text = (EditText)findViewById(R.id.age_text);
        //get请求
        get_button = (Button)findViewById(R.id.get_request);
        get_button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                String name = name_text.getText().toString();
                String age = age_text.getText().toString();
                //将数据存储到URL中
                String url = baseUrl + "?name=" + name + "?age=" + age;
                HttpGet httpGet = new HttpGet(url);
                //生成一个客户端
                HttpClient httpClient = new DefaultHttpClient();
                InputStream inputStream = null;
                try {
                    //发送请求
                    httpResponse = httpClient.execute(httpGet);
                    httpEntity = httpResponse.getEntity();
                    inputStream = httpEntity.getContent();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                    String line = null;
                    while((line = reader.readLine()) != null){
                        result += line;
                    }
                    Log.d("yinazh", "result = " + result);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally{
                    try{
                        inputStream.close();
                    }catch(Exception e){
                        e.printStackTrace();
                    } 
                }        
            }
        });
        //post请求
        post_button = (Button)findViewById(R.id.post_request);
        post_button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                String name = name_text.getText().toString();
                String age = age_text.getText().toString();
                NameValuePair nameVaulePair = new BasicNameValuePair("name", name);
                NameValuePair ageVaulePair = new BasicNameValuePair("age", age);
                List<NameValuePair> contentValuePairList = new ArrayList<NameValuePair>();
                contentValuePairList.add(nameVaulePair);
                contentValuePairList.add(ageVaulePair);
                try{
                    //请求体或响应体//数据单独存储,不放在URL中
                    HttpEntity requestHttpEntity = new UrlEncodedFormEntity(contentValuePairList);
                    HttpPost httpPost = new HttpPost(baseUrl);
                    httpPost.setEntity(requestHttpEntity);
                    HttpClient httpClient = new DefaultHttpClient();
                    InputStream inputStream = null;
                    try {
                        //发送请求
                        httpResponse = httpClient.execute(httpPost);
                        httpEntity = httpResponse.getEntity();
                        inputStream = httpEntity.getContent();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                        String line = null;
                        while((line = reader.readLine()) != null){
                            result += line;
                        }
                        Log.d("yinazh", "result = " + result);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally{
                        try{
                            inputStream.close();
                        }catch(Exception e){
                            e.printStackTrace();
                        } 
                    }    
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        });
    }
}
**********************************************************************



























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值