最近的工作也不是很忙,所以有时间来总结一下Socket一些基本的东西,希望对新学的朋友起到积极的作用。写作的能力不行,本来有很多东西想写,但是到了写的时候就想不起来了。最后会附上一个例子,例子简单模拟了心跳机制。
这里我还是那一句:多去官网,那里有你想要的东西
http://docs.oracle.com/javase/tutorial/networking/sockets/definition.html
在这里不会过多地说关于网络方面的基础,如果有兴趣的朋友,可以看看O’REILLY的《Java网络编程》。
其实两台机器之间的通信有点像两个人的谈话。先来看看下面的一段平时的对话,平时我和女同事间的对话,我们就根据下面一段话来展开本篇文章:
Kitty :Jimmy,早啊
Jimmy:Kitty,早啊
Kitty :周末去东莞爽了吗
Jimmy:哈哈。爽啊。被各种服务了
……..
Jimmy :拜
Kitty : 拜
走了几步….
Lili : Hi, Jimmy
Jimmy : Hi ,Lili
Lili : 听说你周末很爽哦。
Jimmy : 一般般啦
…
Jimmy : 拜
Lili:拜
下面由我来解释这段话的意义。当Kitty,喊出Jimmy的时候,这时我抬起头看着她,因为Jimmy是我的名字,这时我们已经“建立了连接” ,当Kitty说出‘早啊’的时候,我知道她用的是母语中文,出于礼貌我就会马上回复一句中文‘早啊’,因为我知道别人向你问好,你也不能太没礼貌,这样Kitty就完成“发送数据”,而我完成了“接收数据” 并且做出了响应,我和她“交互”了一会后,彼此说了“拜”,然后我们就“关闭了连接”。接着Lili上来搭讪,这时我就像一台服务器,为各位美女提供了各种服务器,回答这个那个问题。。。
(一) 、何为Socket 套接字?
学过网络的同学都知道,两台计算机实现通信,是一个复杂的过程,其中包括数据包、纠错、包重传等等,幸运的是,这些都不需要自己来实现,Socket可以让我们将网络连接视为一种可以读取字节的流,Socket掩盖了网络的底层细节。说白了,Socket就是两台主机之间的一个连接,但是对于写程序的来说,它也许就是一个顶层的API,通过这个API,我们在两台终端间进行通信。如下图(来自google):
上面的图中,描述了一个主机中,应用程序、套接字、协议、端口号之间的逻辑关系。不同类型的套接字与不同类型的底层协议族以及协议族中的不同协议栈相关联,本篇文章只是基于TCP/IP协议的Socket。在Java中,为TCP/IP协议族提供了两个类:Socket和ServerSocket。一个Socket实例代表了TCP连接的一端,简单地说就是一台电脑中的一个应用程序。
客户端Socket有哪些的基本操作:
1) 连接远程机器
2) 发送数据
3) 接收数据
4) 关闭连接
5) 绑定端口
6) 监听入站数据
7) 在所绑定端口上接受来自远程机器的连接。
服务器端ServerSocket:
1) 创建一个新的ServerSocket
2) 使用accept()在指定端口监听入站的连接。accept()会一直阻塞,知道有客户端尝试连接。
3) 根据服务器类型,获取客户端的输出、输入流。
4) 服务器与客户端根据协议交互,直到关闭连接
5) 服务器返回步骤2),等待下一次连接
(二)、消息的发送和接收
从开头的那段对话,我们可以总结出 :
建立连接 消息进行编码 发送消息 接收消息 消息解码 关闭连接 。
看到这里也许你会有疑问,也许你会问人类谈话是“智能”的,我们谈话中,自己能准确判断另外一个人怎样才算说完一句话,并且能做出回答,而套接字间怎么来完成呢?机器是没有那么智能,它不能判断对方什么时候把一句话说完,这些都要我们为机器协商好,比如, 1)当接收到“/n”就说明一句话已经完成。
2)把整句话的长度告诉另外一方。
说到这里,就引入两个概念:
基于定界符(Delimiter-based):消息的结束有由一个唯一的标记指出,即发送者在传输完成后显式添加一个特殊字节序列,这个特殊标记不能在传输的数据中出现。这种方式,这里就不多说了,大家可以去Google一下。
显式长度(Explicit length):在变长字段或消息前附加一个固定大小的字段,用来指示该字段或消息中包含了多少字节。现在大多Socket应用都是采取这种方式。最后的例子也是采取这种方式。
下面的一段核心代码是显式长度(Explicit length)的一种实现:发送消息前先把消息的长度告知对方 (如果对ByteBuffer不明白的,请看前面发表的两篇文章NIO 01 、NIO02)
发送端:
public void setMsg(String sMsg){ try { if(m_handler.socket().isClosed()){ JOptionPane.showMessageDialog(null, "Please reconnect"); return ; } int iLen = sMsg.getBytes("utf-8").length; // 发送消息的长度 m_handler.out().write(BasicTypeConverter.intToByte(iLen)); // 发送消息 m_handler.out().write(sMsg.getBytes("utf-8"), 0 , iLen); m_handler.out().flush(); } catch (IOException e) { e.printStackTrace(); } }
接收端:
// message head info byte[] bHead = new byte[4]; while(true){ if(m_oIn.read(bHead) == -1){ break; } // 获取到消息的长度 int iSize = BasicTypeConverter.bytesToInt(bHead); // 输入流中可读的长度 int iAvailable = m_oIn.available(); ByteBuffer bBuffer = ByteBuffer.allocate(iSize); if(iSize > iAvailable){ // 直到消息接收完成 while(bBuffer.hasRemaining()){ byte[] bb = new byte[iAvailable]; m_oIn.read(bb); bBuffer.put(bb); iAvailable = m_oIn.available(); } }else{ byte[] bb = new byte[iAvailable]; m_oIn.read(bb); bBuffer.put(bb); } bBuffer.flip(); byte[] aB = bBuffer.array(); String sMsg = new String(aB, 0, aB.length, "utf-8"); ServerFrame.m_oFrame.setMsg(sMsg); }
在这里要说一下:避免使用PrintWriter,很多新学的朋友都很喜欢用PrinterWriter,原因1很简单它不会出现乱码,但是大家想过为什么了吗,它只是用了系统默认的编码,万一发送端和接收端系统默认的编码不一致,一样会导致乱码。解决最好的办法,就是把主动权掌握在自己的手里,自己来编码、解码。
最后提供简单的聊天小程序(附件中),还没完完全全完成,只做了一部分,不过可以运行,客户端可以发送消息给服务器端,剩下的部分,如果有兴趣的朋友可以继续完成,如果有必要,我会把剩下的部分再完善,这样做的目的是,为了大家都能学到东西。麻雀虽小,但是内脏俱全,希望新接触的朋友好好看一下,希望对你们有积极的作用。
相关推荐
"Java Socket 02- 常识篇之文件传送"的主题着重于如何使用Socket实现文件的传输。在这个主题中,我们将深入理解Socket的工作原理以及在实际应用中如何构建文件传输的客户端和服务端。 首先,Socket在TCP/IP协议族中...
在Java编程领域,Socket是网络通信的基础,它允许两个或多个应用程序通过TCP/IP协议进行数据交换。本篇文章将深入探讨如何使用Java NIO(非阻塞I/O)来实现阻塞多线程通信,这对于高性能服务器端应用尤其重要。我们...
本篇将详细讲解如何在Java中实现基于Socket的自定义消息协议,以及客户端与服务器端的数据转换与解析过程。 首先,我们来看`SocketClient.java`,这是客户端的代码实现。客户端通常需要以下几个步骤: 1. 创建...
Java提供了丰富的API来处理网络编程,如Socket和ServerSocket类。这部分内容会教你如何建立客户端-服务器通信,发送和接收数据,以及处理网络异常。 在阅读这个“Java技术教程--基础篇”的过程中,你不仅会学习到...
Java的Socket编程和NIO(非阻塞I/O)可以构建可靠的通信机制。 6. **数据存储**:游戏往往需要持久化数据,如用户进度、成就等。学习如何使用数据库(如H2、SQLite)或者文件系统来存储和读取数据。 7. **性能优化...
I/O流是处理输入输出的关键,Java提供了丰富的流类库,如FileInputStream和FileOutputStream用于文件操作,BufferedReader和PrintWriter用于字符流处理,网络编程中的Socket和ServerSocket则用于网络数据交换。...
本篇文章将详细介绍如何在Java项目中集成并使用Socket.IO客户端,以及所需的jar包。 首先,Java中实现Socket.IO客户端的关键在于找到合适的库。目前,Java社区有多个针对Socket.IO的实现,如`java-socket.io-client...
最后,"JAVA程序员必读--基础篇"可能还会涵盖Java标准库中的常用类,如Math类、Date和Calendar类,以及用于网络编程的Socket和ServerSocket。 总之,这个教程将引导初学者逐步进入Java的世界,提供扎实的编程基础,...
网络编程也是Java开发者需要掌握的技能,Socket编程让你能够创建自己的网络应用程序。学习TCP和UDP协议,理解套接字的工作原理,可以帮助你构建网络通信系统。 接着,深入JVM(Java虚拟机)的内部工作机制,如内存...
本篇主要介绍Java中的Socket编程,特别是如何利用Socket进行文件传输。 首先,理解Socket的基本概念。Socket可以被视为网络上的一个端点,它允许两个程序通过网络进行通信。在Java中,`java.net.Socket`类代表...
Java技能百练——网络篇是针对Java开发者在网络编程方面的深入学习和实践。在这个主题中,我们将探讨Java在处理网络通信、数据传输以及网络服务开发等多个关键领域的应用。下面,我们将详细解析Java网络编程的一些...
本篇将深入探讨Java Socket编程及其在构建聊天应用中的应用。 首先,我们要了解TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它确保数据包按照顺序发送,并且在接收端按顺序接收,...
《Java语言程序设计-基础篇、进阶篇(原书第8版)》是一本全面且深入学习Java编程的权威教材。这本书分为基础篇和进阶篇,旨在为读者提供从入门到精通的完整Java学习路径。对于Java编程的初学者和有一定经验的开发者来...
本资源包“Java项目开发实践---网络篇”涵盖了Java进行网络通信的基础与实践,旨在帮助开发者深入理解并掌握相关知识。 1. **Java网络编程基础** Java提供了丰富的API来处理网络通信,主要集中在`java.net`包下。...
本篇文章将深入探讨Java Socket通信的基本概念、工作原理以及如何通过源码实现简单的通信程序。 首先,理解Socket的基本概念。Socket,通常被称为套接字,它是网络通信中的端点,用于标识一台机器上的一个进程,并...
如果你是刚接触Socket编程的新手,希望通过Java语言来掌握Socket的基本原理及应用,那么这篇指南非常适合你。 #### 二、Socket基础知识 **1. Socket是什么?** - **定义:** Socket是一种通信协议,它允许不同...
综上所述,《Java语言程序设计-基础篇-原书第8版》不仅涵盖了Java语言的基础知识,还深入探讨了面向对象编程、类库使用、异常处理、输入输出、多线程和网络编程等高级主题,是一本适合初学者入门和进阶学习的宝贵...
本篇将深入探讨Java Socket的源码,帮助开发者理解其内部工作原理。 1. **Socket的基本概念** - **套接字(Socket)**:套接字是操作系统内核为网络通信提供的接口,可以看作是进程间通信的一种方式,它在客户端和...