17:网络编程

第一  概述

一、概述:

1、网络模型:OSI参考模型和TCP/IP参考模型

2、网络通讯要素:

1)IP地址:InetAddress

.网络中设备的标识

.不易记忆,可用主机名

Internet上的主机有两种方式表示地址:
域名:www.baidu.com,
IP 地址:202.108.35.210

InetAddress 类对象含有一个 Internet 主机地址的域名和IP地址:www.baidu.com。
域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。

2)端口号

.用于标识进程的逻辑地址,不同进程的标识

.有效地址0~65535,其中0~1024系统使用或保留端口

3)传输协议:
通讯规则

.常见协议:TCP、UDP

①UDP(面向无连接)-->聊天、网络视频会议、步话机

  •  将数据及源和目的封装成数据包中,不需要建立连接
  • .每个数据包的大小限制在64k内
  • .因无连接,是不可靠的协议
  • .不需要建立连接,速度快

②TCP(面向连接)-->下载,打电话

  • 建立连接,形成传输数据的通道
  • 在连接中进行大数据量的传输
  • 通过三次握手完成连接,是可靠的协议
  • .必须建立连接,效率会稍低

注:三次握手:第一次本方发送请求,第二次对方确认连接,第三次本方再次发送确认信息告诉对方,这样双方就都知道了,从而才能建立连接

3、通信的步骤:

1)IP:找到需要通讯的IP地址

2)端口:数据要发送到对象指定应用程序,为标识这些应用程序,所以给这些网络应用程序都用数字标识,为方便称呼这个数字,叫做端口,即逻辑端口。每个网络程序都有自己唯一的标识端口。

3)定义通信规则,称之为协议。国际组织定义了通用协议,即TCP/IP。

注意:必须要有数字标识才能将数据发送到应用程序上。因为端口是明确数据需要有哪个应用程序来处理的标识。

看图:

二、网络模型:

1、对于TCP/IP协议,开发处于传输层和网际层

应用层:FTP和HTTP协议等

传输层:UDP和TCP等

网际层:IP

三、网络通信要素:

IP地址:java中对应的是InetAddress类,存在于java.net包中。

InetAddress类:

1、无构造函数,可通过getLocalHost()方法获取InetAddress对象,此方法是静态的,返回此对象。

InetAddress i = InetAddress.getLocalHost();

2、方法:

1)static InetAddress getByName(String host):在给定主机名的情况下获取主机的IP地址

2)String getHostAddress():返回IP地址字符串文本形式,以这个为主,即以IP地址为主。

3)String getHostName():返回IP地址主机名。

3、如何获取任意一台主机的IP地址对象:

  1. public class IPDemo {
  2. public static void main(String[] args) throws UnknownHostException {
  3. // 获取本地主机ip地址对象。
  4. InetAddress ip = InetAddress.getLocalHost();
  5. System.out.println(ip.getHostAddress());//192.168.1.167
  6. System.out.println(ip.getHostName());//PC201508162051
  7. // // 获取其他主机的ip地址对象。只要输入iP或域名
  8. InetAddress byName = InetAddress.getByName("PC201508162051");// PC201508162051/192.168.1.167
  9. InetAddress byName2 = InetAddress.getByName("www.baidu.com");// www.baidu.com/61.135.169.121
  10. System.out.println(byName);
  11. System.out.println(byName2);
  12. }
  13. }

第二  UDP

一、概述:

Socket:

  1. Socket就是为网络服务提供的一种机制
  2. 通讯的两端都必须有Socket(套接字),相当于港口
  3. 网络通讯其实就是Socket间的通讯
  4. 数据在两个Socket间通过IO传输
  5. IP 地址标识 Internet 上的计算机,端口号标识正在计算机上运行的进程(程序)。
    端口号与IP地址的组合得出一个网络套接字。

二、UDP传输:发送端和接收端是两个独立运行的程序

1、UDP传输的流程:

  • .DatagramSocke(创建Socket对象在发送端和接收端通讯)和DatagramPacket(发送端将数据封包,接收端将数据解包)
  • .建立发送端、接收端
  • .建立数据包
  • .调用Socket的发送和接收方法
  • .关闭Socket
DatagramPacket(byte[] buf, int length)接收
          构造 DatagramPacket,用来接收长度为 length 的数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)发送
          构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。

2、方法:

  • 创建 UDPSocket发送服务对象:DatagramSocket(),可不指定端口
  • 创建 UDPSocket接收服务对象:DatagramSocket(int port),
  • 发送:void send(DatagramPacket p)
  • 接收:void receive(DatagramPacket p)

其中DatagramPacket:数据报包用来实现无连接包投递服务的,每条报文仅根据该包中包含的信息从一台机器路由到另一台机器中。

凡是带地址(InetAddress)的都是用于发送包的。

实例:

  1. /*
  2. * 需求:通过udp传输方式,将一段文字发送出去
  3. * 定义一个udp发送端
  4. */
  5. public class UDPSend {
  6. public static void main(String[] args) throws SocketException, Exception {
  7. // 1、建立udp服务,通过DategramSocket对象
  8. DatagramSocket ds = new DatagramSocket(8888);
  9. // 2、确定数据,并封装成数据包DatagramPacket(byte[] buf, int length, InetAddress,address, int port)
  10. byte[] buf = "udp send message come on".getBytes();// 数据 ,转成字节数组
  11. DatagramPacket dp = new DatagramPacket(buf, buf.length,
  12. InetAddress.getByName("192.168.229.1"), 1000);
  13. // 发到哪 InetAddress.getByName("192.168.229.1"),1000别写系统端口
  14. // 3、通过socket服务的send方法将数据包发送出去
  15. ds.send(dp);
  16. // 4、关闭资源
  17. ds.close();
  18. }
  19. }

数据包的方法

 InetAddress getAddress()
          返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
 byte[] getData()
          返回数据缓冲区。
 int getLength()
          返回将要发送或接收到的数据的长度。
  1. /*
  2. * 需求:定义一个应用程序,用于接收udp协议传输的数据并处理
  3. *
  4. * 定义udp接收端口
  5. * 思路:
  6. * 1、定义udp的socket服务,通常会监听一个端口。其实就是给这个接收网络应用程序定义一个数字标识,
  7. * 明确哪些数据过来该应用程序可以处理
  8. * 2、定义一个数据包,用于存储接收到的字节数据,可以方便提取数据中的信息
  9. * 3、通过socket的receive方法将接收到的数据存入以定义好的数据包中
  10. * 4、通过数据包中特有功能,将不同的数据取出
  11. * 5、关闭资源
  12. */
  13. public class UDPReceive {
  14. public static void main(String[] args) throws Exception {
  15. // 1、建立udp的socket服务,并指定端点
  16. DatagramSocket ds = new DatagramSocket(1000);
  17. // 2、定义数据包,用于存储数据
  18. byte[] buf = new byte[1024];
  19. DatagramPacket dp = new DatagramPacket(buf, buf.length);
  20. // 3、通过socket服务的receive方法将接收到的数据存入数据包中
  21. ds.receive(dp);// 阻塞式方法 ,不发送就一直接收
  22. // 4、通过数据包的方法获取其中的数据
  23. // String getHostAddress():返回IP地址字符串文本形式,以这个为主,即以IP地址为主。
  24. String ip = dp.getAddress().getHostAddress();// 获取ip
  25. String data = new String(dp.getData(), 0, dp.getLength());// dp.getData()获取数据,不需要获取1024,获取指定长度就行
  26. int port = dp.getPort();// 获取端口号,这里的端口和ip是发送端的,他是随机的,可以在套接字中指定,不指定系统随机分配
  27. System.out.println(ip + "::" + data + "::" + port);
  28. // 5、关闭资源
  29. ds.close();
  30. }
  31. }

在看一个获取键盘录入的发送端,接收端就不写了,都差不多:

  1. /*  
  2.  * 发送键盘录入信息  
  3.  */  
  4. public class UDPSend2 {  
  5.     public static void main(String[] args) throws Exception {  
  6.         DatagramSocket ds = new DatagramSocket();  
  7.         BufferedReader bfr = new BufferedReader(  
  8.                 new InputStreamReader(System.in));  //转换流,转成字节
  9.         String line = null;  
  10.       
  11.        byte[] buf = null;  
  12.         DatagramPacket dp = null;  
  13.         while ((line = bfr.readLine()) != null) {  
  14.             buf = line.getBytes();  
  15.             dp = new DatagramPacket(buf, buf.length,  
  16.                     InetAddress.getByName("192.168.229.1"), 10000);
  17. //192.168.1.255广播地址,在这个频段里的所有ip都可以接收,聊天室  
  18.             ds.send(dp);  
  19.               
  20.             if("886".equals(line)){  
  21.                 break;  
  22.             }  
  23.         }  
  24.         ds.close();  
  25.         buf.clone();  
  26.     }  
  27. }  

练习:编写一个简单的聊天程序:

分析:

有收数据的部分,有发数据的部分,这两部分需要同时执行,那就需要多线程技术,一个线程控制接收,一个线程控制发。

因为收和发的动作不一致,所以要定义两个run方法,而且这个两个方法要封装到不同的类中。

  1. public class UDPChatDemo {  
  2.     public static void main(String[] args) throws IOException {  
  3.         DatagramSocket sendSocket = new DatagramSocket();  
  4.         DatagramSocket ReceiveSocket = new DatagramSocket(10002);  
  5.           
  6.         new Thread(new ChatSend(sendSocket)).start();  
  7.         new Thread(new ChatReceive(ReceiveSocket)).start();  
  8.     }  
  9. }  
  1. /*  
  2.  * 聊天的发送端  
  3.  */  
  4. public class ChatSend implements Runnable{  
  5.       
  6.     private DatagramSocket ds;  
  7.       
  8.     public ChatSend(DatagramSocket ds){  
  9.         this.ds = ds;  
  10.     }  
  11.   
  12.     @Override  
  13.     public void run() {  
  14.         BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));  
  15.         byte[] buf = null;  
  16.         String line = null;  
  17.         try {  
  18.             while((line=bfr.readLine()) != null){  
  19.                 buf = line.getBytes();  
  20.                 DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.255"), 10002);  
  21.                 ds.send(dp);  
  22.             }  
  23.         } catch (UnknownHostException e) {  
  24.             e.printStackTrace();  
  25.         } catch (IOException e) {  
  26.             e.printStackTrace();  
  27.         }finally{  
  28.             ds.close();  
  29.             try {  
  30.                 bfr.close();  
  31.             } catch (IOException e) {  
  32.                 e.printStackTrace();  
  33.             }  
  34.         }  
  35.     }  
  36.       
  37. }  
  1. /*  
  2.  * 聊天,接收端  
  3.  */  
  4. public class ChatReceive implements Runnable{  
  5.       
  6.     private DatagramSocket ds;  
  7.       
  8.     public ChatReceive(DatagramSocket ds){  
  9.         this.ds = ds;  
  10.     }  
  11.   
  12.     @Override  
  13.     public void run() {  
  14.         while(true){  
  15.             byte[] buf = new byte[1024];  
  16.             DatagramPacket dp = new DatagramPacket(buf, buf.length);  
  17.             try {  
  18.                 ds.receive(dp);  
  19.                 String ip = dp.getAddress().getHostAddress();  
  20.                 String data = new String(dp.getData(),0,dp.getLength());  
  21.                 int port = dp.getPort();  
  22.                 System.out.println(ip + "::" + data + "::" + port);  
  23.             } catch (IOException e) {  
  24.                 e.printStackTrace();  
  25.             }  
  26.         }  
  27.     }  
  28.   
  29. }  

第三  TCP传输

TCP传输:

1、流程:

  • Socket(客户端)和ServiceSocket服务端()
  • 建立客户端和服务端
  • 建立连接后,通过socket中的IO流进行数据的传输

关闭socket

2、方法:

1)创建客户端对象: Socket(String host,int port),指定要接收的IP地址和端口号

2)创建服务端对象:ServerSocket(int port):指定接收的客户端的端口

3)Socket accept():侦听并接受到此套接字的连接,服务器用于接收客户端socket对象的方法

注:服务器没有socket流,也就没有读写操作的流,服务器是通过获取到客户端的socket流然后获取到其中的读写方法,对数据进行操作的,也正是因为这样服务器与客户端的数据操作才不会错乱

4)void shutdownInput():此套接字的输入流至于“流的末尾”

5)void shutdownOutput():禁用此套接字的输出流

6)InputStream getInputStream():返回此套接字的输入流

7)OutputStream getOutputStream():返回套接字的输出流

实例:

定义tcp的服务端

  • 建立服务端的socket服务,ServerSocket,并监听一个端口
  • 获取连接过来的客服端对象,通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。
  • 客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。
  • 关闭服务端(可选)
  1. public class TCPServerDemo {
  2. public static void main(String[] args) throws IOException {
  3. // 建立服务端的socket服务,并监听一个端口
  4. ServerSocket ss = new ServerSocket(10003);
  5. // 通过accept方法获取连接过来的客户端对象
  6. Socket socket = ss.accept();
  7. String ip = socket.getInetAddress().getHostAddress();
  8. System.out.println(ip + "......connected");
  9. // 获取客户端发过来的数据,那么要使用客户端对象的读取流来获取数据
  10. InputStream in = socket.getInputStream();
  11. byte[] buf = new byte[1024];
  12. int len = in.read(buf);
  13. System.out.println(new String(buf, 0, len));
  14. socket.close();// 关闭客户端
  15. ss.close();// 关闭服务端,可选的操作
  16. }
  17. }

tcp分为客户端和服务端,客服端对象的对象是socket,服务端对应的是serversoceket

  • 客户端,在建立的时候就可以去连接指定的主机
  • 因为tcp是面向连接的,所以在建立socket时就需要有服务端存在
  • 并连接成功,形成通路,才能在该通道上传输数据
  1. public class TCPClientDemo {
  2. public static void main(String[] args) throws Exception {
  3. //1、创建客户端的socket服务,指定目的主机和端口
  4. Socket socket = new Socket("192.168.229.1", 10003);
  5. //2、获取socket的输出流,用于发送数据
  6. OutputStream out = socket.getOutputStream();
  7. //3、发送数据
  8. out.write("tcp client send message come on".getBytes());
  9. socket.close();
  10. }
  11. }

示例二:下面是客户端和服务端互动的例子,建立一个文本转换机制,就是客户端把从键盘录入的数据发送给服务器,服务器将数据转为大写再发给客户端

  1. /*  
  2.  * 需求:建立一个文本转换服务器。  
  3.  * 客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。  
  4.  * 而且客户度可以不断的进行文本转换。当客户端输入over时,转换结束。  
  5.  *   
  6.  * 分析:  
  7.  * 客户端  
  8.  * 既然是操作设备上的数据,那就可以使用IO技术,并按照io操作规律来思考  
  9.  * 源:键盘录入  
  10.  * 目的:网络设备,网络输出流  
  11.  * 而且操作的是文本数据,可以用字符流  
  12.  *   
  13.  * 步骤: 
  14.  * 1、建立服务  
  15.  * 2、获取键盘输入  
  16.  * 3、将数据发给客户端  
  17.  * 4、获取服务端返回的数据  
  18.  * 5、结束,关闭资源  
  19.  */  
  20. class TransClient {  
  21.     public static void main(String[] args) throws UnknownHostException,  
  22.             IOException {  
  23.         Socket s = new Socket(InetAddress.getLocalHost(), 10005);  
  24.         BufferedReader bfrb = new BufferedReader(new InputStreamReader(  
  25.                 System.in));  
  26.   
  27.         // 定义目的,将数据写入socket输出流,发给服务器  
  28.         OutputStream out = s.getOutputStream();  
  29.         OutputStreamWriter ow = new OutputStreamWriter(out);  
  30.         BufferedWriter bfw = new BufferedWriter(ow);  
  31.   
  32.         // 定义读取流  
  33.         InputStream in = s.getInputStream();  
  34.         InputStreamReader is = new InputStreamReader(in);  
  35.         BufferedReader bfr = new BufferedReader(is);  
  36.   
  37.         String line = null;  
  38.         while ((line = bfrb.readLine()) != null) {  
  39.             bfw.write(line);  
  40.             bfw.newLine();  
  41.             bfw.flush();  
  42.   
  43.             // 读取数据  
  44.             String data = bfr.readLine();  
  45.             System.out.println(data);  
  46.         }  
  47.   
  48.         bfrb.close();  
  49.         s.close();  
  50.     }  
  51. }  
  52.   
  53. /*  
  54.  * 服务端: 源:socket读取流 目的:socket输出流。  
  55.  */  
  56. class TransServer {  
  57.     public static void main(String[] args) throws IOException {  
  58.         ServerSocket ss = new ServerSocket(10005);  
  59.         Socket s = ss.accept();  
  60.   
  61.         String ip = s.getInetAddress().getHostAddress();  
  62.         System.out.println(ip + "....connected");  
  63.   
  64.         InputStream in = s.getInputStream();  
  65.         InputStreamReader isr = new InputStreamReader(in);  
  66.         BufferedReader bfr = new BufferedReader(isr);  
  67.   
  68.         // 目的。socket输出流。将大写数据写入到socket输出流,并发送给客户端。  
  69.         BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(  
  70.                 s.getOutputStream()));  
  71.           
  72.         String line = null;  
  73.         while((line=bfr.readLine()) != null){  
  74.             bufOut.write(line.toUpperCase());  
  75.             bufOut.newLine();  
  76.             bufOut.flush();  
  77.         }  
  78.         s.close();  
  79.         ss.close();  
  80.     }  
  81. }  
  82.   
  83. public class TCPTransText{  
  84.     public static void main(String[] args) {  
  85.         new TransClient();  
  86.         new TransServer();  
  87.     }  
  88. }  

示例三:TCP复制文件

1、客户端:

源:硬盘上的文件;目的:网络设备,即网络输出流。若操作的是文本数据,可选字符流,并加入高效缓冲区。若是媒体文件,用字节流。

2、服务端:

源:socket读取流;目的:socket输出流。

3、出现的问题:

现象:

a.文件已经上传成功了,但是没有得到服务端的反馈信息。

b.即使得到反馈信息,但得到的是null,而不是“上传成功”的信息

原因:

a.因为客户端将数据发送完毕后,服务端仍然在等待这读取数据,并没有收到结束标记,就会一直等待读取。

b.上个问题解决后,收到的不是指定信息而是null,是因为服务端写入数据后,也需要刷新,才能将信息反馈给客服端。

解决:

a.方法一:定义结束标记,先将结束标记发送给服务端,让服务端接收到结束标记,然后再发送上传的数据。但是这样定义可能会发生定义的标记和文件中的数据重复而导致提前结束。

方法二:定义时间戳,由于时间是唯一的,在发送数据前,先获取时间,发送完后在结尾处写上相同的时间戳,在服务端,接收数据前先接收一个时间戳,然后在循环中判断时间戳以结束标记。

方法三:通过socket方法中的shutdownOutput(),关闭输入流资源,从而结束传输流,以给定结束标记。这里主要用这个方法。

  1. /*  
  2.  * 客户端  
  3.  */  
  4. class TextClient {  
  5.     public static void main(String[] args) throws UnknownHostException,  
  6.             IOException {  
  7.         Socket s = new Socket(InetAddress.getLocalHost(), 10007);  
  8.   
  9.         File file = new File("AwtDemo.java");  
  10.   
  11.         BufferedReader bfr = new BufferedReader(new FileReader(file));  
  12.   
  13.         // 将数据写入到socket流中  
  14.         PrintWriter out = new PrintWriter(s.getOutputStream(), true);  
  15.   
  16.         String line = null;  
  17.         while ((line = bfr.readLine()) != null) {  
  18.             out.println(line);  
  19.         }  
  20.         // 关闭客户端的输出流。相当于给流中加入一个结束标记-1.  
  21.         // 结束标记很重要,不然TCP中程序停不下来  
  22.         s.shutdownOutput();  
  23.   
  24.         // 接收服务端发过来的数据  
  25.         BufferedReader bfrs = new BufferedReader(new InputStreamReader(  
  26.                 s.getInputStream()));  
  27.   
  28.         String data = bfrs.readLine();  
  29.         System.out.println(data);  
  30.   
  31.         bfr.close();  
  32.         s.close();  
  33.     }  
  34. }  
  35.   
  36. class TextServer {  
  37.     public static void main(String[] args) throws IOException {  
  38.         ServerSocket ss = new ServerSocket(10007);  
  39.         Socket s = ss.accept();// 接收客户端的socket流  
  40.         String ip = s.getInetAddress().getHostAddress();  
  41.         System.out.println(ip + "....connected");  
  42.   
  43.         //建立读取客户端数据的流  
  44.         BufferedReader bfr = new BufferedReader(new InputStreamReader(  
  45.                 s.getInputStream()));  
  46.         //建立文件,关联流  
  47.         PrintWriter out = new PrintWriter(new FileWriter("server.java"),true);  
  48.           
  49.         String line = null;  
  50.         while((line=bfr.readLine()) != null){  
  51.             out.println(line);  
  52.         }  
  53.           
  54.         //建立给客户端回馈机制  
  55.         PrintWriter outToC = new PrintWriter(s.getOutputStream(),true);  
  56.         outToC.println("上传成功");  
  57.           
  58.         out.close();  
  59.         s.close();  
  60.         ss.close();  
  61.     }  
  62. }  

第四  实际应用

一、TCP并发执行请求

一)图片上传:

第一、客户端:

1、创建服务端点

2、读取客户端以后图片数据

3、通过Socket输出流将数据发给服务端

4、读取服务端反馈信息

5、关闭客户端

第二、服务端

对于客户端并发上传图片,服务端如果单纯的使用while(true)循环式有局限性的,当A客户端连接上以后,被服务端获取到,服务端执行具体的流程,这时B客户端连接就只有等待了,因为服务端还未处理完A客户端的请求,还有循环来回执行下须accept方法,所以暂时获取不到B客户端对象,那么为了可让多个客户端同时并发访问服务端,那么服务端最好就是将每个客户端封装到一个单独的线程,这样就可以同时处理多个客户端的请求。如何定义线程呢?只要明确每个客户端要在服务端执行的代码即可,将改代码存入到run方法中。

  1. /*  
  2.  * 客户端  
  3.  */  
  4. class PicCilent2 {  
  5.     public static void main(String[] args) throws UnknownHostException,  
  6.             IOException {  
  7.         File file = new File(args[0]);  
  8.         Socket s = new Socket("192.168.229.1", 10010);  
  9.         // 读取文件数据  
  10.         BufferedInputStream bfr = new BufferedInputStream(new FileInputStream(  
  11.                 file));  
  12.         // 将数据写到socket流中,传递给服务端  
  13.         BufferedOutputStream out = new BufferedOutputStream(s.getOutputStream());  
  14.   
  15.         byte[] buf = new byte[1024];  
  16.         int len = 0;  
  17.         while ((len = bfr.read(buf)) != -1) {  
  18.             out.write(buf, 0, len);  
  19.         }  
  20.         s.shutdownInput();// 结束标记  
  21.   
  22.         // 接收服务端反馈数据  
  23.         InputStream in = s.getInputStream();  
  24.         byte[] bufin = new byte[1024];  
  25.         int num = in.read(bufin);  
  26.         System.out.println(new String(bufin, 0, num));  
  27.   
  28.         bfr.close();  
  29.         s.close();  
  30.     }  
  31. }  
  32.   
  33. /*  
  34.  *   
  35.  * 服务端:  
  36.  */  
  37. class PicThread implements Runnable {  
  38.   
  39.     private Socket s;  
  40.   
  41.     PicThread(Socket s) {  
  42.         this.s = s;  
  43.     }  
  44.   
  45.     @Override  
  46.     public void run() {  
  47.         int count = 1;  
  48.         String ip = s.getInetAddress().getHostAddress();  
  49.         try {  
  50.             System.out.println(ip + "....connected");  
  51.   
  52.             InputStream in = s.getInputStream();  
  53.   
  54.             File dir = new File("c:\\");  
  55.   
  56.             File file = new File(dir, ip + "(" + (count) + ")" + ".jpg");  
  57.   
  58.             while (file.exists())  
  59.                 file = new File(dir, ip + "(" + (count++) + ")" + ".jpg");  
  60.   
  61.             FileOutputStream fos = new FileOutputStream(file);  
  62.   
  63.             byte[] buf = new byte[1024];  
  64.   
  65.             int len = 0;  
  66.             while ((len = in.read(buf)) != -1) {  
  67.                 fos.write(buf, 0, len);  
  68.             }  
  69.   
  70.             OutputStream out = s.getOutputStream();  
  71.   
  72.             out.write("上传成功".getBytes());  
  73.   
  74.             fos.close();  
  75.   
  76.             s.close();  
  77.         } catch (Exception e) {  
  78.             throw new RuntimeException(ip + "上传失败");  
  79.         }  
  80.     }  
  81.   
  82. }  
  83.   
  84. class Picserver2 {  
  85.     public static void main(String[] args) throws IOException {  
  86.         ServerSocket ss = new ServerSocket(10011);  
  87.         while (true) {  
  88.             Socket s = ss.accept();  
  89.   
  90.             new Thread(new PicThread(s)).start();  
  91.         }  
  92.     }  
  93. }  

二、其他方式访问服务器:

1、浏览器

在浏览器地址栏输入你的IP和你的服务器的端口号,这就可以成功通过浏览器访问自己的服务器了。

2、telnet

telnet是windows提供的远程登录工具,可以连接服务器的任意一台主机,并在通过dos命令行配置服务器 访问方式:IP 端口号--> 192.168.229.1 端口号

2、 客户端:浏览器。

服务端:Tomcat服务器。

启动tomcat服务器,自己写点数据用于服务器返回给客户端的数据,这里是html文件,自己写一个简单的html文件放在tomcat的webapps目录下就可以

3、客户端:自定义。(图形界面)

服务端:Tomcat服务器。


第五  原理

最常见的客户端:

浏览器 :IE。

最常见的服务端:

服务器:Tomcat。

原理:

自定义服务端,使用已有的客户端IE,了解一下客户端给服务端发了什么请求?

  1. public class MyTomcat {
  2. /**
  3. * @param args
  4. * @throws IOException
  5. */
  6. public static void main(String[] args) throws IOException {
  7. ServerSocket ss = new ServerSocket(9090);
  8. Socket s = ss.accept();
  9. System.out.println(s.getInetAddress().getHostAddress()+".....connected");
  10. InputStream in = s.getInputStream();
  11. byte[] buf = new byte[1024];
  12. int len = in.read(buf);
  13. String text = new String(buf,0,len);
  14. System.out.println(text);
  15. //给客户端一个反馈信息。
  16. PrintWriter out = new PrintWriter(s.getOutputStream(),true);
  17. out.println("<font color=‘red‘ size=‘7‘>欢迎光临</font>");
  18. s.close();
  19. ss.close();
  20. }
  21. }

发送的请求是(输出的text):

GET / HTTP/1.1  请求行  请求方式  /myweb/1.html  请求的资源路径   http协议版本。

请求消息头 . 属性名:属性值

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: */*

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

//Host: www.huyouni.com:9090

Connection: Keep-Alive

//空行

//请求体。

知道了发送了什么,那么就可以模拟一个浏览器

  1. public class MyBrowser {
  2. /**
  3. * @param args
  4. * @throws IOException
  5. * @throws UnknownHostException
  6. */
  7. public static void main(String[] args) throws UnknownHostException, IOException {
  8. Socket s = new Socket("192.168.1.100",8080);
  9. //模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
  10. PrintWriter out = new PrintWriter(s.getOutputStream(),true);
  11. out.println("GET /myweb/1.html HTTP/1.1");
  12. out.println("Accept: */*");
  13. out.println("Host: 192.168.1.100:8080");
  14. out.println("Connection: close");
  15. out.println();
  16. out.println();
  17. InputStream in = s.getInputStream();
  18. byte[] buf = new byte[1024];
  19. int len = in.read(buf);
  20. String str =new String(buf,0,len);
  21. System.out.println(str);
  22. s.close();
  23. //http://192.168.1.100:8080/myweb/1.html
  24. }
  25. }

//服务端发回应答消息。

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>

可是浏览器并没有显示应答消息属性信息这些内容,因为浏览器有自己的解析引擎,Java封装了一个类URL可以解析引擎

  1. public class URLDemo {
  2. /**
  3. * @param args
  4. * @throws IOException
  5. */
  6. public static void main(String[] args) throws IOException {
  7. String str_url = "http://192.168.1.100:8080/myweb/1.html";
  8. URL url = new URL(str_url);
  9. // System.out.println("getProtocol:"+url.getProtocol());
  10. // System.out.println("getHost:"+url.getHost());
  11. // System.out.println("getPort:"+url.getPort());
  12. // System.out.println("getFile:"+url.getFile());
  13. // System.out.println("getPath:"+url.getPath());
  14. // System.out.println("getQuery:"+url.getQuery());
  15. //这一部简化了下面的俩步
  16. // InputStream in = url.openStream();
  17. //获取url对象的Url连接器对象。将连接封装成了对象:java中内置的可以解析的具体协议的对象+socket.
  18. URLConnection conn = url.openConnection();
  19. // String value = conn.getHeaderField("Content-Type");
  20. // System.out.println(value);
  21. // System.out.println(conn);
  22. //sun.net.www.protocol.http.HttpURLConnection:http://192.168.1.100:8080/myweb/1.html
  23. InputStream in = conn.getInputStream();
  24. byte[] buf = new byte[1024];
  25. int len = in.read(buf);
  26. String text = new String(buf,0,len);
  27. System.out.println(text);
  28. in.close();
  29. }
  30. }

网络结构,

  • C/S  client/server

特点:

该结构的软件,客户端和服务端都需要编写。

可发成本较高,维护较为麻烦。

好处:

客户端在本地可以分担一部分运算。

  • B/S  browser/server

特点:

该结构的软件,只开发服务器端,不开发客户端,因为客户端直接由浏览器取代。

开发成本相对低,维护更为简单。

缺点:所有运算都要在服务端完成。


小知识点

1、InetSocketAddress对象(IP+端口)

2、ServerSocket对象中的构造函数:

ServerSocket(int port,int backlog),其中的backlog表示队列的最大长度,即最多连入客户端的个数,即最大连接数。

3、在进行浏览器输入网址访问一台主机所做的操作:

如http://192.168.229.1:8080/myweb/demo.html,一般直接输入主机名:http://baidu.com等,那么如何通过主机名获取IP地址,从而连接到这台主机的呢?这就需要将主机名翻译成IP地址,即域名解析:DNS(存的是主机名和IP相对应的键值对)

在进行访问的时候,会现在本地的hosts文件(C:\WINDOWS\system32\drivers\etc\hosts)中找对应的映射,若有,则直接返回请求,若无,则到公网的映射列表即DNS中找对应的映射,找到后,将主机名对应的IP地址返回给本机,本机通过这个IP地址找到对应的服务器。

域名解析示意图:

host应用:

1、可屏蔽一些恶意网址,即将对应的映射关系写入hosts中,将IP地址改为本机的回环地址,那么会直接找到hosts,就不会将请求发送出去了。

2、不让软件更新,可以越过一些收费软件的限制。

3、把经常上的网站写入文件中,提高访问速率。

来自为知笔记(Wiz)

时间: 2024-10-11 12:09:07

17:网络编程的相关文章

网络编程TCP/IP实现客户端与客户端聊天

一.TCP/IP协议 既然是网络编程,涉及几个系统之间的交互,那么首先要考虑的是如何准确的定位到网络上的一台或几台主机,另一个是如何进行可靠高效的数据传输.这里就要使用到TCP/IP协议. TCP/IP协议(传输控制协议)由网络层的IP协议和传输层的TCP协议组成.IP层负责网络主机的定位,数据传输的路由,由IP地址可以唯一的确定Internet上的一台主机.TCP层负责面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象. 二.TCP与UDP TCP是一种面向连接的保证可靠传输的协议

(一)理解网络编程和套接字

学习<TCP/IP网络编程> 韩 尹圣雨 著 金国哲 译 套接字类似电话 一.服务器端套接字(listening套接字)---接电话套接字 ①调用socket函数---安装电话机 #include <sys/socket.h> int socket(int domain, int type, int protocol); //成功时返回文件描述符,失败时返回-1 ②调用bind函数---分配电话号码 #include <sys/socket.h> int bind(in

Linux C高级编程——网络编程基础(1)

Linux高级编程--BSD socket的网络编程 宗旨:技术的学习是有限的,分享的精神是无限的. 一网络通信基础 TCP/IP协议簇基础:之所以称TCP/IP是一个协议簇,是由于TCP/IP包括TCP .IP.UDP.ICMP等多种协议.下图是OSI模型与TCP/IP模型的对照.TCP/IP将网络划分为4层模型:应用层.传输层.网络层和网络接口层(有些书籍将其分为5层,即网络接口层由链路层和物理层组成) (1)网络接口层:模型的基层.负责数据帧的发送已接收(帧是独立的网络信息传输单元).网络

arpa/inet.h所引起的Segmentation fault及网络编程常见的头文件

最近在学习Linux网络编程方面的知识,感觉还是有些困难.主要是对协议过程的理解,还有socket的API的理解不够深刻.今天复习编写了一个TCP的服务端和客户端的程序实现client.c从命令行参数中获得一个字符串发给服务器,然后接收服务器返回的已处理的字符串并打印. server.c 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h>

用java网络编程中的TCP方式上传文本文件及出现的小问题

自己今天刚学java网络编程中的TCP传输,要用TCP传输文件时,自己也是遇到了一些问题,抽空把它整理了一下,供自己以后参考使用. 首先在这个程序中,我用一个客户端,一个服务端,从客户端上传一个文本文件给服务端,服务端接收数据并显示“上传成功”给客户端. 客户端: 1 import java.io.BufferedReader; 2 import java.io.FileReader; 3 import java.io.IOException; 4 import java.io.InputStr

网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服务器进程B1同时为客户进程A1.A2和B2提供服务. Socket概述 ①   所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通过“套接字”向网络发出请求或者应答网络请求. ②   Socket是连接运行在网络上的两个程序间的双向通信的端点. ③  

iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄

前言:本篇讲解,在前篇iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载的基础上,使用输出流代替文件句柄实现大文件断点续传.    在实际开发中,输入输出流用的比较少,但是用起来也是很方便的.iOS开发用到的输入输出流和在Java中的输入输出流是几乎一样的,本质也是一个意思:将网络返回的数据当做流来处理.    输入输出的理解:输入到哪里?输出到哪里?这个问题不难理解,输入输出是要站着服务器角度来思考的,下面用图来解释:    代码关键词: 1.在接收到响应头的代理

unix网络编程代码(2)

继续贴<unix网络编程>上的示例代码.这次是一个反射程序,反射是客户端讲用户输入的文本发送到服务器端,服务器端读取客户端发过来的文本消息,然后原封不动的把文本消息返回给客户端.使用tcp协议连接客户端和服务端,我已经在我的阿里云服务器上测试过了,能够完美运行. 首先是头文件wrap.h,在该头文件中,声明了封装部分网络编程套接字api的包裹函数,以及某些宏定义. 1 #ifndef WRAP_H_ 2 #define WRAP_H_ 3 4 #include <stdio.h>

Java学习之网络编程实例

转自:http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html 多谢分享 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在学习网络编程以前,很多初学者可能觉得网络编程是比较复杂的系统工程,需要了解很多和网络相关的基础知识,其实这些都不是很必需的.首先来问一个问题:你 会打手机吗?很多人可能说肯定会啊,不就是按按电话号码

第三章 网络编程

终于学到网络编程了! 先上图和程序: 这是今天写的TCP的实现 服务器和客户端分别在两台电脑 这是服务器图: 这是服务器程序: 1 #-*- coding:utf-8 -*- 2 from socket import * #导入socket所有属性 3 from time import ctime #导入ctime() 4 5 6 host = '' #HOST 变量为空,表示bind()函数可以绑定在所有有效的地址上. 7 port = 21000 #设置端口 8 bufsize = 1024