Java网络编程菜鸟进阶:TCP和套接字入门

JDK 提供了对 TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Datagram Protocol,用户数据报协议)这两个数据传输协议的支持。本文开始探讨 TCP。

TCP 基础知识

在“服务器-客户端”这种架构中,服务器和客户端各自维护一个端点,两个端点需要通过网络进行数据交换。TCP 为这种需求提供了一种可靠的流式连接,流式的意思是传出和收到的数据都是连续的字节,没有对数据量进行大小限制。一个端点由 IP 地址和端口构成(专业术语为“元组 {IP 地址, 端口}”)。这样,一个连接就可以由元组 {本地地址, 本地端口, 远程地址, 远程端口} 来表示。

连接过程

在 TCP 编程接口中,端点体现为 TCP 套接字。共有两种 TCP 套接字:主动和被动,“被动”状态也常被称为“侦听”状态。服务器和客户端利用套接字进行连接的过程如下:

1、服务器创建一个被动套接字,开始循环侦听客户端的连接。

2、客户端创建一个主动套接字,连接服务器。

3、服务器接受客户端的连接,并创建一个代表该连接的主动套接字。

4、服务器和客户端通过步骤 2 和 3 中创建的两个主动套接字进行数据传输。

下面是连接过程的图解:

一个简单的 TCP 服务器

JDK 提供了 ServerSocket 类来代表 TCP 服务器的被动套接字。下面的代码演示了一个简单的 TCP 服务器(多线程阻塞模式),它不断侦听并接受客户端的连接,然后将客户端发送过来的文本按行读取,全文转换为大写后返回给客户端,直到客户端发送文本行 bye:

  1. public class TcpServer implements Runnable {
  2. private ServerSocket serverSocket;
  3. public TcpServer(int port) throws IOException {
  4. // 创建绑定到某个端口的 TCP 服务器被动套接字。
  5. serverSocket = new ServerSocket(port);
  6. }
  7. @Override
  8. public void run() {
  9. while (true) {
  10. try {
  11. // 以阻塞的方式接受一个客户端连接,返回代表该连接的主动套接字。
  12. Socket socket = serverSocket.accept();
  13. // 在新线程中处理客户端连接。
  14. new Thread(new ClientHandler(socket)).start();
  15. } catch (IOException ex) {
  16. ex.printStackTrace();
  17. }
  18. }
  19. }
  20. }
  21. public class ClientHandler implements Runnable {
  22. private Socket socket;
  23. public ClientHandler(Socket socket) {
  24. this.socket = Objects.requireNonNull(socket);
  25. }
  26. @Override
  27. public void run() {
  28. try (Socket s = socket) {  // 减少代码量的花招……
  29. // 包装套接字的输入流以读取客户端发送的文本行。
  30. BufferedReader in = new BufferedReader(new InputStreamReader(
  31. s.getInputStream(), StandardCharsets.UTF_8));
  32. // 包装套接字的输出流以向客户端发送转换结果。
  33. PrintWriter out = new PrintWriter(new OutputStreamWriter(
  34. s.getOutputStream(), StandardCharsets.UTF_8), true);
  35. String line = null;
  36. while ((line = in.readLine()) != null) {
  37. if (line.equals("bye")) {
  38. break;
  39. }
  40. // 将转换结果输出给客户端。
  41. out.println(line.toUpperCase(Locale.ENGLISH));
  42. }
  43. } catch (IOException ex) {
  44. ex.printStackTrace();
  45. }
  46. }
  47. }

阻塞模式的编程方式简单,但存在性能问题,因为服务器线程会卡死在接受客户端的 accept() 方法上,不能有效利用资源。套接字支持非阻塞模式,现在暂时略过。

一个简单的 TCP 客户端

JDK 提供了 Socket 类来代表 TCP 客户端的主动套接字。下面的代码演示了上述服务器的客户端:

  1. public class TcpClient implements Runnable {
  2. private Socket socket;
  3. public TcpClient(String host, int port) throws IOException {
  4. // 创建连接到服务器的套接字。
  5. socket = new Socket(host, port);
  6. }
  7. @Override
  8. public void run() {
  9. try (Socket s = socket) {  // 再次减少代码量……
  10. // 包装套接字的输出流以向服务器发送文本行。
  11. PrintWriter out = new PrintWriter(new OutputStreamWriter(
  12. s.getOutputStream(), StandardCharsets.UTF_8), true);
  13. // 包装套接字的输入流以读取服务器返回的文本行。
  14. BufferedReader in = new BufferedReader(new InputStreamReader(
  15. s.getInputStream(), StandardCharsets.UTF_8));
  16. Console console = System.console();
  17. String line = null;
  18. while ((line = console.readLine()) != null) {
  19. if (line.equals("bye")) {
  20. break;
  21. }
  22. // 将文本行发送给服务器。
  23. out.println(line);
  24. // 打印服务器返回的文本行。
  25. console.writer().println(in.readLine());
  26. }
  27. // 通知服务器关闭连接。
  28. out.println("bye");
  29. } catch (IOException ex) {
  30. ex.printStackTrace();
  31. }
  32. }
  33. }

从 JDK 文档可以看到,ServerSocket 和 Socket 在初始化的时候,可以设定一些参数,还支持延迟绑定。这些东西对性能和行为都有所影响。后续两篇文章将分别详解这两个类的初始化。

原文链接:http://www.blogjava.net/shinzey/archive/2012/01/04/367846.html

【Java】Java网络编程菜鸟进阶:TCP和套接字入门的更多相关文章

  1. 网络编程(基于udp协议的套接字/socketserver模块/进程简介)

    一.基于UDP协议的套接字 TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据.相对TCP,UDP则是面向无连接的协议. 使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就 ...

  2. Java网络编程(一)Socket套接字

    一.基础知识 1.TCP:传输控制协议. 2.UDP:用户数据报协议. 二.IP地址封装 1.InetAddress类的常用方法 getLocalHost() 返回本地主机的InetAddress对象 ...

  3. TCP/IP网络编程之优雅地断开套接字

    基于TCP套接字的半关闭 Linux的close函数和Windows的closesocket函数意味着完全断开连接,完全断开连接不仅指无法传输数据,而且也不能接收数据.因此,在某些情况下,通信一方调用 ...

  4. 【UNIX网络编程(一)】套接字地址结构、网络字节顺序和地址转换功能

    介绍:应该用在网络编程实现每个套接字地址结构.所以主套接字地址结构后前提网络计划编制,地址结构可以在两个方向上发送:从工艺到内核和内核处理.构中的二进制值之间进行转换. 大多数套接字函数都须要一个指向 ...

  5. windows网络编程(1)同步套接字

    1.socket是应用程序与网络驱动程序的桥梁,在应用程序中创建socket,将数据交付给socket即完成数据传输,剩下的任务由socket和网络驱动程序完成: 2.套接字类型:SOCK_STREA ...

  6. 【Unix网络编程】chapter8基本UDP套接字编程

    chapter8基本UDP套接字编程 8.1 概述 典型的UDP客户端/服务端的函数调用 8.2 recvfrom和sendto函数 #include <sys/socket.h> ssi ...

  7. Java之网络编程UDP和TCP

    注*部分转来的 第1章 网络通信协议 通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样.在计算机网 ...

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

    自己今天刚学java网络编程中的TCP传输,要用TCP传输文件时,自己也是遇到了一些问题,抽空把它整理了一下,供自己以后参考使用. 首先在这个程序中,我用一个客户端,一个服务端,从客户端上传一个文本文 ...

  9. java网络编程socket\server\TCP笔记(转)

    java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅     1 TCP的开销 a ...

随机推荐

  1. 机房收费系统个人重构关于SQLHelper

    近期在敲机房,对于SQLHelper也是心里有些怵,由于原来没用过,可是看了一些博客和资料后发现,假设不用这个类,会大大添加代码量,并且,事实上它并不新,它是一个有多个关于数据库增删改查操作的语句函数 ...

  2. [每日一题] 11gOCP 1z0-052 :2013-09-1 RMAN-- repair failure........................................A20

    转载请注明出处:http://blog.csdn.net/guoyjoe/article/details/10859315 正确答案:D 一.模拟上题的错误: 1.删除4号文件 [oracle@myd ...

  3. cocos2d-x3.0-结合TH脚本引擎

    近期自己在研究手机游戏开发,呵呵.引擎就选择了cocos2d-x,略微看了下感觉好像非常不错的样子. 写个一般的游戏,全然能够了.工作量也不会非常大,相对来说开发非常轻松了. 在脚本引擎的选择其中,当 ...

  4. Annotation Type @bean,@Import,@configuration使用--官方文档

    @Target(value={METHOD,ANNOTATION_TYPE}) @Retention(value=RUNTIME) @Documented public @interface Bean ...

  5. UIPickView的简单介绍

    UIPickView的简单介绍 设置UIPickView的时候,我们主要需要设置一下下面的两个属性 UIPickerView *pickView1; pickView1 = [[UIPickerVie ...

  6. 为什么我选择使用 Blocks(块)

    扯淡:到了新公司接手新框架之后,发现大量的使用Blocks,之前很多时候都是使用代理,突然面对这个陌生的语法,特地科普总结了一番. 什么是Blocks 一句话概括就是,带有局部变量的匿名函数(即不带名 ...

  7. shell脚本实现冒泡排序 分类: 学习笔记 linux ubuntu 2015-07-10 14:16 79人阅读 评论(0) 收藏

    手动输入一行字符串,并对其排序. 脚本如下: #!/bin/bash #a test about sort echo "please input a number list" re ...

  8. Java基础知识强化之集合框架笔记47:Set集合之TreeSet保证元素唯一性和比较器排序的原理及代码实现(比较器排序:Comparator)

    1. 比较器排序(定制排序) 前面我们说到的TreeSet的自然排序是根据集合元素的大小,TreeSet将它们以升序排列. 但是如果需要实现定制排序,比如实现降序排序,则要通过比较器排序(定制排序)实 ...

  9. mysql 安装employees db的步骤

    因为准备要开始学习ASP.NET的高级部分,所以今晚想安装一个数据库示例,百度发现原来mysql有个employees db 但是单纯按照网上的方法,也是没有办法导入的,所以写了这篇博文,作为笔记. ...

  10. Shell - 特殊变量

    $0 表示所执行程序的路径名. [huey@huey-K42JE ~]$ ll ~/bin total 4 -rwxrwxr-x 1 huey huey 21 Oct 24 14:39 hello [ ...