[关闭]
@lemonguge 2015-06-29T13:16:42.000000Z 字数 6038 阅读 490

Java网络编程(二)

Socket

UDP传输协议的应用可以类比为对讲机,按住对讲机的开关就可以说话,而不关心有没有人听他说话,不需要建立连接。TCP传输协议可以类比为打电话,只有形成传输数据的通道才能进行数据的传输,需要通过三次握手完成连接。什么是三次握手呢?觉个例子,我和你分别在两座山头上,互相喊话,假设我先喊了一句“听到我说话了吗?”,如果你听到了,这就说明我向你说话是可行的,但是我不知道你听到没有,因此你说“我听到了”,这样我就知道我向你说话是可行的,同时你向我说话也是可行的,可你并不知道你向我说话,我到底听到了没有,所以我应该再向你说一句“OK,我知道啦”,这样你也知道你向我说话是可行的。


TCP传输协议

TCP传输协议对应的端点Socket有两个,分别为客户端套接字Socket和服务器套接字ServerSocket。当建立连接之后,通过客户端套接字Socket中的IO流(socket流)进行数据的传输。

TCP的客户端

同样明确客户端的实现思路:

  1. 创建TCP客户端Socket套接字端点,应该明确服务器的IP和端口,必须先运行服务器端,这将建立起连接;
  2. 如果连接建立成功,则数据传输通道已建立(socket流在底层建立完成,可以通过getInputStream()getOutputStream()来获取输入和输出字节流);
  3. 使用输出流,将数据写到服务器;
  4. 关闭Socket套接字,释放资源。
  1. import java.io.IOException;
  2. import java.io.OutputStream;
  3. import java.net.Socket;
  4. public class Client {
  5. public static void main(String[] args) throws IOException {
  6. // 要先运行服务端,否则将不能连接成功(Connection refused: connect)
  7. Socket socket = new Socket("JieHong-PC", 8011);
  8. // 获取socket流中的输出流
  9. OutputStream out = socket.getOutputStream();
  10. // 使用输出流将指定的数据写出去
  11. out.write("TCP传输协议:客户端运行".getBytes());
  12. // 关闭资源
  13. socket.close();
  14. }
  15. } ///~

TCP的服务端

同样明确服务端的实现思路:

  1. 创建TCP服务端ServerSocket套接字端点,应该明确服务器所侦听的端口;
  2. 通过accept()方法获取连接过来的客户端对象;
  3. 通过客户端对象获取socket流来读取客户端发来的数据;
  4. 关闭客户端,服务端一般不关闭。
  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.net.ServerSocket;
  4. import java.net.Socket;
  5. public class Server {
  6. public static void main(String[] args) throws IOException {
  7. // 创建服务端对象,侦听8011端口
  8. ServerSocket ss = new ServerSocket(8011);
  9. // 获取连接过来的客户端对象
  10. Socket s = ss.accept(); // 阻塞式方法
  11. String ip = s.getInetAddress().getHostAddress();
  12. int port = s.getPort();
  13. // 获取输入流来读取 客户端发过来的数据
  14. InputStream in = s.getInputStream();
  15. byte[] buf = new byte[1024];
  16. int length = in.read(buf);
  17. String data = new String(buf, 0, length);
  18. System.out.println(ip + ":" + port + ":" + data);
  19. s.close();
  20. ss.close(); // 一般不关闭
  21. }
  22. } ///~

TCP的服务端与客户端的交互

当客户端向服务器端发送请求,服务端收到请求后并处理,接着返回请求处理后的信息给客户端。

  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.io.OutputStream;
  4. import java.net.ServerSocket;
  5. import java.net.Socket;
  6. // 服务端
  7. public class Server {
  8. public static void main(String[] args) throws IOException {
  9. // 创建服务端对象,侦听8011端口
  10. ServerSocket ss = new ServerSocket(8011);
  11. // 获取连接过来的客户端对象
  12. Socket s = ss.accept(); // 阻塞式方法
  13. String ip = s.getInetAddress().getHostAddress();
  14. int port = s.getPort();
  15. // 获取输入流来读取 客户端发过来的数据
  16. InputStream in = s.getInputStream();
  17. byte[] buf = new byte[1024];
  18. int length = in.read(buf);
  19. String data = new String(buf, 0, length);
  20. System.out.println(ip + ":" + port + ":" + data);
  21. // 使用客户端socket对象的输出流给客户端返回数据
  22. OutputStream out = s.getOutputStream();
  23. out.write("处理完成".getBytes());
  24. s.close();
  25. ss.close(); // 一般不关闭
  26. }
  27. } /* Output:
  28. 192.168.2.109:50447:TCP传输协议:客户端运行
  29. *///:~
  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.io.OutputStream;
  4. import java.net.Socket;
  5. public class Client {
  6. public static void main(String[] args) throws IOException {
  7. // 要先运行服务端,否则将不能连接成功
  8. Socket socket = new Socket("JieHong-PC", 8011);
  9. // 获取socket流中的输出流
  10. OutputStream out = socket.getOutputStream();
  11. // 使用输出流将指定的数据写出去
  12. out.write("TCP传输协议:客户端运行".getBytes());
  13. // 读取服务端返回的数据,使用socket读取流
  14. InputStream in = socket.getInputStream();
  15. byte[] buf = new byte[1024];
  16. int length = in.read(buf);
  17. String back = new String(buf, 0, length);
  18. System.out.println(back);
  19. // 关闭资源
  20. socket.close();
  21. }
  22. } /* Output:
  23. 处理完成
  24. *///:~

当我们从客户端Socket获取到InputStreamOutputStream对象时,便可以使用Java I/O的装饰类来方便我们操作。

当我们上传文件到服务器端,上传完成之后,需要调用shutdownOutput()方法来告诉服务端,客户端写完了,否则服务器无法知道文件的结束标识符。

浏览器客户端

我们可以通过浏览器进行访问,那么浏览器就是一个客户端,我们可以自己写一个服务器端,来看看浏览器会给我发送哪些信息。

  1. import java.io.BufferedOutputStream;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.PrintWriter;
  5. import java.net.ServerSocket;
  6. import java.net.Socket;
  7. public class BrowserServer {
  8. public static void main(String[] args) throws IOException {
  9. ServerSocket ss = new ServerSocket(8012);
  10. Socket s = ss.accept();
  11. // 获取ip
  12. String ip = s.getInetAddress().getHostAddress();
  13. System.out.println(ip + " connected..");
  14. InputStream in = s.getInputStream();
  15. byte[] buf = new byte[1024];
  16. int len = in.read(buf);
  17. String text = new String(buf, 0, len);
  18. System.out.println(text);
  19. System.out.println("--END--");
  20. PrintWriter pw = new PrintWriter(new BufferedOutputStream(
  21. s.getOutputStream()), true);
  22. pw.println("<font color='red' size='7'>请求已收到</font>"); //在浏览器可以看到返回的信息
  23. s.close();
  24. ss.close();
  25. }
  26. } /* Output: // 浏览器输入http://www.jiehong.com:8012
  27. 127.0.0.1 connected..
  28. GET / HTTP/1.1
  29. Accept: text/html, application/xhtml+xml, */*
  30. Accept-Language: zh-CN
  31. User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
  32. Accept-Encoding: gzip, deflate
  33. Host: www.jiehong.com:8012
  34. DNT: 1
  35. Connection: Keep-Alive
  36. --END--
  37. *///:~

由于我已经在本地域名解析配置了"127.0.0.1 www.jiehong.com",所以看到的IP是"127.0.0.1"。


URL和URLConnection

java.net包中包含两个有趣的类:URL类和URLConnection类,这两个类可以用来创建客户端到Web服务器(HTTP服务器)的连接,以下是一个简单的演示:

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStreamReader;
  4. import java.net.URL;
  5. import java.net.URLConnection;
  6. public class URLDemo {
  7. public static void main(String[] args) throws IOException {
  8. URL url = new URL("http://www.baidu.com"); // http是协议不可省(no protocol)
  9. System.out.println(url.getProtocol()); // 输出http
  10. // 获取url对象的Url连接器对象
  11. URLConnection urlConnection = url.openConnection();
  12. // 读取从服务端返回的数据
  13. BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
  14. String line = null;
  15. while ((line = br.readLine()) != null)
  16. System.out.println(line);
  17. br.close();
  18. }
  19. } ///:~

以上的小示例,输出很多所以不展示。默认情况下URLConnection发送一个HTTP GET请求到Web服务器。如果你想发送一个HTTP POST请求,要调用URLConnection.setDoOutput(true)方法,接下来你就可以打开URLConnectionOutputStream,可以使用这个OutputStream向相应的HTTP请求中写任何数据,但你要记得将其转换成URL编码。

通过URL读取本地文件

URL也被叫做统一资源定位符,URL类是另外一种打开文件的方式,下面是一个如何使用URL类打开一个本地文件系统文件的例子:

  1. import java.io.BufferedReader;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.InputStreamReader;
  6. import java.net.URL;
  7. import java.net.URLConnection;
  8. // D盘有一个file.txt文件,文件有两行内容,分别为“123你好”和“abc”
  9. public class URLDemo {
  10. public static void main(String[] args) throws IOException {
  11. ReadFileByURL();
  12. }
  13. public static void ReadFileByURL() throws IOException {
  14. URL url = new URL("file:" + File.separator + "d:" + File.separator + "file.txt");
  15. System.out.println("Protocol:" + url.getProtocol());
  16. URLConnection urlConnection = url.openConnection();
  17. InputStream input = urlConnection.getInputStream();
  18. BufferedReader br = new BufferedReader(new InputStreamReader(input));
  19. String line = null;
  20. while ((line = br.readLine()) != null)
  21. System.out.println(line);
  22. }
  23. } /* Output:
  24. Protocol:file
  25. 123你好
  26. abc
  27. *///:~

对Java网络编程的Socket讲解结束,这一块的内容不多且很简单。后记:很早就想写写这一块的内容了,尤其是当我向着手写Java nio的时候,这种想法特别强烈,写于2015年6月29日。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注