一、Socket简单介绍

Socket通信作为Java网络通讯的基础内容,集中了异常、I/O流模式等众多知识点。学习Socket通信,既能够了解真正的网络通讯原理,也能够增强对I/O流模式的理解。

1)Socket通信分类

(一)基于TCP的Socket通信:使用流式套接字,提供可靠、面向连接的通信流。

(二)基于UDP的Socket通信:使用数据报套接字,定义一种无连接服务,数据之间通过相互独立的报文进行传输,是无序的,并且不保证可靠、无差错。

2)Socket概念理解

金山词霸中对Socket名词解释:插座、灯座、窝,引申到计算机科学称为"套接字"。至于为什么要翻译成"套接字",可以参考:

Socket曾经被翻译为"软插座",表明此处说的插座不是实际生活中的那种插座(硬插座),而是在计算机领域抽象出来的接口。如果在客户端插座和服务器端插座之间连一条线(也就是数据交互的信道),那么客户端就能够与服务器端进行数据交互。

二、基于TCP的Socket通信理论基础

基于TCP/IP协议的网络编程,就是利用TCP/IP协议在客户端和服务器端之间建立通信链接来实现数据交换。 具体的编程实现步骤如下:

1)服务器端创建其提供服务的端口号,即服务器端中提供服务的应用程序接口名称。

服务器端ServerSocket: ServerSocket serverSocket = new ServerSocket(int port, int backlog);  ServerSocket作用是向操作系统注册相应协议服务,申请端口并监听这个端口是否有链接请求。其中port是端口号,backlog是服务器最多允许链接的客户端数。注册完成后,服务器分配此端口用于提供某一项进程服务。

2)服务器端(Server)和客户端(Client)都创建各自的Socket对象。

服务器端Socket:  Socket socket = serverSocket.accept();  服务器端创建一个socket对象用于等待客户端socket的链接(accept方法是创建一个阻塞队列,只有客户端socket申请链接到服务器后,服务器端socket才能收到消息) 。如果服务器端socket收到客户端的链接请求,那么经过"三次握手"过程,建立客户端与服务器端的连接。如果连接不成功,则抛出异常(详见模块三)。

客户端Socket: Socket socket = new Socket(String host, int port);  客户端创建按一个socket对象用于链接具体服务器host的具体服务端口port,用于获得服务器进程的相应服务。

经过三次握手后,一个Socket通路就建立起来。此时,服务器端和客户端就可以开始通讯了。

3)服务器端和客户端打开链接到Socket通路的I/O流,按照一定协议进行数据通信。

协议就是指发送与接受数据的编码格式(计算机网络中为:语义、同步)。简单说就是输入和输出的流必须匹配。

开启网络输入流:网络输入流指的是从socket通道进入计算机内存的流。    socket.getInputStream();  返回值InputStream 输入字节流

开启网络输出流:网络输出流指的是从计算机内存走出到socket通道的流。 socket.getOutputStream(); 返回值OutputStream 输出字节流

为了通讯方便,往往将低级流包装成高级流进行服务端与客户端之间的交互。

4)通信完毕,关闭网络流

一般而言,服务器端的流失不用关闭的,当然在某些条件下(比如服务器需要维护)也是需要关闭的。而客户端一般都需要关闭。

三、Socket异常类

网络通讯中会遇到很多种错误,比如通讯中断、服务器维护拒绝访问等等。下面稍微总结一下Socket通讯中常见的异常类。

1)java.net.SocketTimeoutException套接字超时异常。常见原因:网络通路中断,链接超时;

2)java.net.UnknowHostException未知主机异常。常见原因:客户端绑定的服务器IP或主机名不存在;

3)java.net.BindException绑定异常。常见原因:端口被占用;

4)java.net.ConnectException连接异常。常见原因:服务器未启动,客户端申请服务;服务器拒绝服务,即服务器正在维护;

四、Java建立Socket通讯

1)服务器端与客户端建立连接

1 packageday05;2

3 importjava.io.IOException;4 importjava.net.ServerSocket;5 importjava.net.Socket;6

7 /**8 * 服务器端9 *@authorforget40610 *11 */

12 public classServer {13

14 privateServerSocket serverSocket;15

16 /** 在操作系统中注册8000端口服务,并监听8000端口 */17 publicServer() {18 try{19 /*public ServerSocket(int port, int backlog)20 * port表示端口号,backlog表示最多支持连接数*/

21 serverSocket = new ServerSocket(8000, 3);22 } catch(IOException e) {23 e.printStackTrace();24 }25 }26

27 /**与客户端交互*/

28 public voidstart() {29 try{30 System.out.println("等待用户链接...");31 /*创建Socket对象: public Socket accept()32 * 等待客户端链接,直到客户端链接到此端口*/

33 Socket socket =serverSocket.accept();34 System.out.println("链接成功,可以通讯!");35 } catch(IOException e) {36 //TODO Auto-generated catch block

37 e.printStackTrace();38 }39 }40

41 public static voidmain(String[] args) {42 Server server = newServer();43 server.start();44 }45 }46

47 ==============================================

48

49 packageday05;50

51 importjava.io.IOException;52 importjava.net.Socket;53 importjava.net.UnknownHostException;54

55 /**

56 * 客户端57 *@authorforget40658 *59 */

60 public classClient {61

62 privateSocket socket;63

64 /** 申请与服务器端口连接 */65 publicClient() {66 try{67 /*请求与服务器端口建立连接68 * 并申请服务器8000端口的服务*/

69 socket = new Socket("localhost", 8000);70 } catch(UnknownHostException e) {71 e.printStackTrace();72 } catch(IOException e) {73 e.printStackTrace();74 }75 }76

77 /** 与服务器交互 */

78 public voidstart() {79

80 }81

82 public static voidmain(String[] args) {83 Client client = newClient();84 client.start();85 }86 }

服务器端结果:

五、Java实现C/S模式Socket通讯

1)客户端向服务器端发送消息(单向通信):服务器只能接受数据,客户端只能发送数据。这是由于socket绑定了从客户端到服务器的一条通信通路。

1 packageday05;2

3 importjava.io.BufferedReader;4 importjava.io.IOException;5 importjava.io.InputStream;6 importjava.io.InputStreamReader;7 importjava.net.ServerSocket;8 importjava.net.Socket;9

10 /**

11 * 服务器端12 *@authorforget40613 *14 */15 public classServer {16

17 privateServerSocket serverSocket;18

19 /** 在操作系统中注册8000端口服务,并监听8000端口*/20 publicServer() {21 try{22 /*public ServerSocket(int port, int backlog)23 * port表示端口号,backlog表示最多支持连接数*/

24 serverSocket = new ServerSocket(8000, 3);25 } catch(IOException e) {26 e.printStackTrace();27 }28 }29

30 /**与客户端单向交互*/31 public voidstart() {32 System.out.println("等待用户链接...");33 try{34 /*创建Socket对象: public Socket accept()35 * 等待客户端链接,直到客户端链接到此端口*/

36 Socket socket =serverSocket.accept();37 System.out.println("用户链接成功,开始通讯!");38

39 /*服务器开始与客户端通讯*/

40 while(true) {41 //开启服务器socket端口到服务器内存的网路输入字节流

42 InputStream is43 =socket.getInputStream();44 //在服务器内存中将网络字节流转换成字符流

45 InputStreamReader isr46 = newInputStreamReader(47 is, "UTF-8"

48 );49 //包装成按行读取字符流

50 BufferedReader br51 = newBufferedReader(isr);52

53 /*中途网络可能断开54 * 1)Windows的readLine会直接抛出异常55 * 2)Linux的readLine则会返回null*/

56 String msg = null;57 if((msg = br.readLine()) != null) {58 System.out.println("客户端说:" +

59 msg60 );61 }62

63 }64

65 } catch(IOException e) {66 System.out.println("链接失败");67 e.printStackTrace();68 }69 }70

71 public static voidmain(String[] args) {72 Server server = newServer();73 server.start();74 }75 }76

77 ===========================================

78

79 packageday05;80

81 importjava.io.IOException;82 importjava.io.OutputStream;83 importjava.io.OutputStreamWriter;84 importjava.io.PrintWriter;85 importjava.net.Socket;86 importjava.net.UnknownHostException;87 importjava.util.Scanner;88

89 /**90 * 客户端91 *@authorforget40692 *93 */94 public classClient {95

96 privateSocket socket;97

98 /** 申请与服务器端口连接 */

99 publicClient() {100 try{101 /*请求与服务器端口建立连接102 * 并申请服务器8000端口的服务*/

103 socket = new Socket("localhost", 8000);104 } catch(UnknownHostException e) {105 e.printStackTrace();106 } catch(IOException e) {107 e.printStackTrace();108 }109 }110

111 /** 与服务器单向交互 */112 public voidstart() {113 try{114 //开启客户端内存到客户端socket端口的网络输出流

115 OutputStream os116 =socket.getOutputStream();117 //将客户端网络输出字节流包装成网络字符流

118 OutputStreamWriter osw119 = new OutputStreamWriter(os, "UTF-8");120 //将输出字符流包装成字符打印流

121 PrintWriter pw122 = new PrintWriter(osw, true);123 //来自键盘的标准输入字节流

124 Scanner sc = newScanner(System.in);125 while(true) {126 //打印来自键盘的字符串(字节数组)

127 pw.println(sc.nextLine());128 }129

130 } catch(IOException e) {131 e.printStackTrace();132 }133 }134

135 public static voidmain(String[] args) {136 Client client = newClient();137 client.start();138 }139 }

客户端输入:

服务器端结果:

2)客户端与服务器端双向通信:客户端与服务器交互,能够实现服务器对客户端的应答,这更像是P2P模式。此时,双方socket端口均绑定来回一对通信通路。

1 packageday05;2

3 importjava.io.BufferedReader;4 importjava.io.IOException;5 importjava.io.InputStreamReader;6 importjava.io.OutputStreamWriter;7 importjava.io.PrintWriter;8 importjava.net.ServerSocket;9 importjava.net.Socket;10 importjava.util.Scanner;11

12 /**

13 * 服务器端14 *@authorforget40615 *16 */

17 public classServer {18

19 privateServerSocket serverSocket;20

21 /**在操作系统中注册8000端口服务,并监听8000端口*/

22 publicServer() {23 try{24 /*public ServerSocket(int port, int backlog)25 * port表示端口号,backlog表示最多支持连接数*/

26 serverSocket = new ServerSocket(8000, 3);27 } catch(IOException e) {28 e.printStackTrace();29 }30 }31

32 /**与客户端单向交互*/

33 @SuppressWarnings("resource")34 public voidstart() {35 System.out.println("等待用户链接...");36 try{37 /*创建Socket对象: public Socket accept()38 * 等待客户端链接,直到客户端链接到此端口*/

39 Socket socket =serverSocket.accept();40 System.out.println("用户链接成功,开始通讯!");41

42 /*服务器接收客户端数据*/

43 InputStreamReader isr44 = newInputStreamReader(45 socket.getInputStream(),46 "UTF-8"

47 );48 BufferedReader br49 = newBufferedReader(isr);50 String msgReceive = null;51 String msgSend = null;52

53 /*服务器向客户端发送数据*/

54 OutputStreamWriter osw55 = newOutputStreamWriter(56 socket.getOutputStream(),57 "UTF-8"

58 );59 PrintWriter pw60 = new PrintWriter(osw, true);61 Scanner sc = newScanner(System.in);62

63 while(true) {64 if((msgReceive = br.readLine()) != null) {65 System.out.println("客户端说:" +msgReceive);66 }67

68 if((msgSend = sc.nextLine()) != null) {69 pw.println(msgSend);70 }71 }72

73 } catch(IOException e) {74 System.out.println("链接失败");75 e.printStackTrace();76 }77 }78

79 public static voidmain(String[] args) {80 Server server = newServer();81 server.start();82 }83 }84

85 ============================================

86

87 packageday05;88

89 importjava.io.BufferedReader;90 importjava.io.IOException;91 importjava.io.InputStreamReader;92 importjava.io.OutputStreamWriter;93 importjava.io.PrintWriter;94 importjava.net.Socket;95 importjava.net.UnknownHostException;96 importjava.util.Scanner;97

98 /**

99 * 客户端100 *@authorforget406101 *102 */

103 public classClient {104

105 privateSocket socket;106

107 /**申请与服务器端口连接*/

108 publicClient() {109 try{110 /*请求与服务器端口建立连接111 * 并申请服务器8000端口的服务*/

112 socket = new Socket("localhost", 8000);113 } catch(UnknownHostException e) {114 e.printStackTrace();115 } catch(IOException e) {116 e.printStackTrace();117 }118 }119

120 /**与服务器单向交互*/

121 @SuppressWarnings("resource")122 public voidstart() {123 try{124 /*客户端向服务器发送数据*/

125 OutputStreamWriter osw126 = newOutputStreamWriter(127 socket.getOutputStream(),128 "UTF-8"

129 );130 PrintWriter pw131 = new PrintWriter(osw, true);132 Scanner sc = newScanner(System.in);133

134 /*客户端接收服务器数据*/

135 InputStreamReader isr136 = newInputStreamReader(137 socket.getInputStream(),138 "UTF-8"

139 );140 BufferedReader br141 = newBufferedReader(isr);142 String msgReceive = null;143 String msgSend = null;144

145 while(true) {146 if((msgSend = sc.nextLine()) != null) {147 pw.println(msgSend);148 }149 if((msgReceive = br.readLine()) != null) {150 System.out.println("服务器说:" +msgReceive);151 }152 }153

154 } catch(IOException e) {155 System.out.println("链接失败!");156 e.printStackTrace();157 }158 }159

160

161 public static voidmain(String[] args) {162 Client client = newClient();163 client.start();164

165 }166 }

PS: 只是初步实现,有些bug没有改进。类似QQ的完善版本代码会在后续的文章中更新。

六、心得体会

上述代码实现的是C/S模型的简化版本,即P2P模式---客户端与服务器端一对一进行交互通信。事实上,服务器可以并行与多台客户机进行数据收发与交互,这需要运用到Java多线程的知识,这将会在后续文章中分析。

I/O流模式的选取原则:

1. 选择合适的节点流。在Socket网络编程中,节点流分别是socket.getInputStream和socket.getOutputStream,均为字节流。

1.1)选择合适方向的流。输入流socket.getInputStream、InputStreamReader、BufferedReader;输出流socket.getOutputStream、OutputStreamWriter、PrintWriter。

1.2)选择字节流和字符流。网络通信在实际通信线路中传递的是比特流(字节流);而字符流只会出现在计算机内存中。

2. 选择合适的包装流。在选择I/O流时,节点流是必须的,而包装流则是可选的;节点流类型只能存在一种,而包装流则能存在多种(注意区分:是一种或一对,而不是一个)。

2.1)选择符合功能要求的流。如果需要读写格式化数据,选择DataInputStream/DataOutputStream;而BufferedReader/BufferedWriter则提供缓冲区功能,能够提高格式化读写的效率。

2.2)选择合适方向的包装流。基本与节点流一致。当选择了多个包装流后,可以使用流之间的多层嵌套功能,不过流的嵌套在物理实现上是组合关系,因此彼此之间没有顺序。

注明:文章系作者原创,转载请注明出处

socket网络编程 java_Java Web 基础(一) 基于TCP的Socket网络编程相关推荐

  1. 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

    转自即时通讯网:http://www.52im.net/ 本文原作者:"水晶虾饺",原文由"玉刚说"写作平台提供写作赞助,原文版权归"玉刚说" ...

  2. 基于TCP的socket编程网络掉线重连

    基于TCP的socket编程   sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW):基于TCP的socke ...

  3. 2018-2019 20165208 网络对抗 Exp8 Web基础

    目录 2018-2019 20165208 网络对抗 Exp8 Web基础 实验内容 基础问题回答 实践过程记录 1. Apache准备 2. Web前端HTML 3. Web前端javascipt ...

  4. 麻瓜编程Python Web基础

    文章目录[隐藏] 教程介绍 教程介绍 你并非没有能力学习编程,而是大多数课程没有把事情讲简单,也许你缺少的只是一些点拨. 在我们的课程里,你会发现生动的类比贯穿其中,复杂的事情变简单.本课程以实战项目 ...

  5. Java基于TCP(Socket)协议的网络语音聊天

    Java基于TCP协议的网络语音聊天 本聊天是基于tcp协议进行的,其本质为:本地录音->将录音通过网络编程转发给他人->他人进行录音的播放. 所需知识:多线程,基于tcp协议的网络编程 ...

  6. 《网络攻防》Web基础

    20145224陈颢文 <网络攻防>Web基础 基础问题回答 什么是表单: 表单是一个包含表单元素的区域.表单元素是允许用户在表单中输入信息的元素.表单在网页中主要负责数据采集功能. 浏览 ...

  7. 用C#实现基于TCP协议的网络通讯

    TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编程.然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实 ...

  8. 基于TCP协议的网络摄像头的设计与实现

    一.摘要 基于TCP协议的网络摄像头的设计大部分和博文"基于UDP协议的网络摄像头的设计与实现"相同,本篇博文采用的TCP协议栈为NicheStack协议栈(同理,可使用LWIP协 ...

  9. Java中基于TCP通过socket嵌套字连接方式传送文件

    这里写目录标题 Java中通过socket连接传送文件 前言 socket嵌套字 发送方 接收方 总结 Java中通过socket连接传送文件 前言 在项目的开发中经常遇到需要传送文件的情况,有时候是 ...

最新文章

  1. 前后端分离必备工具:Swagger快速搞定(整合SpringBoot详细教程)
  2. Centos7如何轻松配置yum国内源
  3. VLAN,trunk,以太网通道
  4. python红色_python把红玫瑰变成蓝色女巫,将,红色,转化,为,蓝色妖姬
  5. js笔记(9)之定时器数字时钟延时提示框
  6. 冲刺二阶段-个人总结03
  7. Vlookup函数多返回值处理
  8. 高效管理CrossOver容器里的程序
  9. 5、SpringBoot+MyBaits+Maven+Idea+pagehelper分页插件
  10. 【OpenCV学习笔记】【编程实例】四(获取一个或多个感兴趣区域)
  11. 中级软件评测师考什么
  12. 网络协议介绍(NetBIOS,NETBEUI,IPX/SPX,TCP/IP)
  13. 深入浅出hibernate_夏昕_hibernate别名完成ResultSet和实体的映射
  14. 交换机Trunk详解
  15. 解决Excel表格输入身份证号码显示异常的问题
  16. 百胜中国拟2025年前开1000家Lavazza咖啡店​;别样肉客开始陆续进驻中国山姆会员商店 | 知消...
  17. sql语句查询A表有而B表没有的数据
  18. 操作系统4————进程同步
  19. python显示透明图片背景
  20. 一个P2P未跑路平台老板的自白

热门文章

  1. Java中Comparable接口与Comparator接口
  2. Spring Cloud Stream多RabbitMQ实例配置时报错no default binder has been set
  3. 计算机组成原理与汇编语言程序设计课后答案,计算机组成原理与汇编语言程序设计课后习题及解答(详解)...
  4. MySQL备份-mysqldump命令
  5. js ---- 数组操作
  6. linux 将结果放入数组,linux-如何将值添加到bash数组?
  7. IDEA2018部署jeesite3完美运行教程
  8. 如何把一个整数转化成数组_「leetcode891」给定一个整数数组 A,考虑 A 的所有非空子序列...
  9. IDEA两步删除版本控制
  10. java定时任务设置为每天执行一次,首次还是好的,到第二天就不执行了的原因