关于Socket的简单解析

最近在研究Socket的通信,感觉坑很多,多,多。。所以今天就和大家来简单分享下Socket的使用方式,以及关于Socket的几个比较重要,容易被小伙伴们忽略且常用的方法,

好了,进入今天的正题。

在Android中,像 http请求、socket通信等等都属于网络通信的一种方式。http请求底层也是socket的一种实现方式。

我们今天的主题会围绕在Android中使用Socket来实现通信。

说到通信,可以简单理解为两方相互交流。双方即手机和远程服务器,我们可以把手机当做客户端,因为我们要与”遥远的东方“发消息。此时手机可以作为一个Socket端。

那么“遥远的东方”就是服务器端,即ServerSocket(服务端Socket)。这样当客户端Socket和服务端ServerSocket建立了联系之后,双方都确定了对方的身份,证明大家都是认识的是朋友。才可以进行“悄悄话的交流”。这里我们提到要双方确认,其实在Socket中作为三次握手,下面我们来分析Socket与服务端ServerSocket建立联系的三次握手过程:

(1)第一次握手:建立连接时,客户端Socket向服务端ServerSocket发送SYN
包,并进入SYN_SEND状态,等待服务器B确认。这个过程,就好比我向你打电话,我的手机号通过信号到了你的手机上并显示
156XXXXXXXX来电,此时要等你确认这个手机号。

(2)第二次握手:此时服务端收到客户端的SYN包,与客户端的SYN进行确认,确认后,服务端向客户端发送个SYN包,即SYN+ACK
包。服务端进入SYN_RECV状态。这个过程就好比,当收到某人的来电后,我确认手机号是我的朋友,此时我要接通他的电话。

(3)第三次握手:客户端收到服务端发送过来的SYN + ACK包,此时客户端像服务端再发送一个ACK确认包。此时发送完毕后,客户端与服务端就进入了ESTABLISHED状态,完成通信前的三次握手。这个过程就好比,当我接通了电话后,我问对方是XXX吗?对方说是的!OK啦,那接下来就是要通信的内容了。

至此,在Socket与ServerSocket进行通信前的准备工作就完成了。现在我们就可以进行通信交流了,接下来看看我们该如何使用。

因为Socket是属于Java的net。所以在Android中使用的方式是一样的。首先,我们需要建立双方,即创建客户端Socket和服务器端ServerSocket:

(1)创建客户端Socket:

在上述代码中,我们首先来看InetSocketAddress这个类。InetSocketAddress继承了SocketAddress类。该类从上述代码中我们就能看出来它的作用,没错,就是用于指定我们需要连接服务器的地址。我们可以使用它的构造函数来指定要连接的服务器IP和Port
(ip地址和端口号)。继续往下看,此时我们创建一个Socket实例,并调用了Socket的一些属性方法。最后通过Socket的connect()方法来根据InetSocketAddress进行连接服务器。过程很简单,核心就是需要我们去指定InetSocketAddress中的ip和port。简单分析完流程,我们来具体分析Socket的这几个核心方法:

在JDK1.4中共有8个Socket方法可以设置。这8个方法对应了8个属性选项,它们都定义在Java.net.SocketOptions接口中。定义如下:

    public final static int TCP_NODELAY = 0x0001;

public final static int SO_REUSEADDR = 0x04;

public final static int SO_LINGER = 0x0080;

public final static int SO_TIMEOUT = 0x1006;

public final static int SO_SNDBUF = 0x1001;

public final static int SO_RCVBUF = 0x1002;

public final static int SO_KEEPALIVE = 0x0008;

public final static int SO_OOBINLINE = 0x1003;

从上面看到,除TCP_NODELAY以为,其他都是以SO开头。 上面的这8个成员变量分别提供set和get方法来操作,即对应了我们上面调用的这几个方法:

(1)setSoTimeOut:设置客户端Socket读取数据的超时时长。即当与服务端建立联系后,此时要接收服务端返回的数据,设置该方法可以限定客户端等待服务端发送数据的时间,如果超过了该时长,系统会抛出一个InterruptedIOException异常。在抛出异常后,输入流并未关闭,你可以继续通过read方法读取数据。 如果将timeout设为0,就意味着read将会无限等待下去,直到服务端程序关闭这个Socket.这也是timeout的默认值。

(2)setKeepAlive:该方法指定检测与服务器的链接状态。如果设置参数为true,即打开该设置,此时,客户端会利用空闲的连接每隔两个小时向服务端发送一次数据包进行连接验证服务器是否仍处于活动状态。如果此时服务端未响应,客户端会在第11分钟后继续发送一个验证包,如果在12分钟内服务端还未响应,此时客户端就会执行关闭连接的操作。如果将该设置项关闭,客户端Socket在服务器无效的情况下可能会长时间不会关闭,占据资源。默认情况下是关闭的。

(3)setTcpNoDelay:该方法很有聪明,如果开启该设置,当客户端发送数据给服务端时,发送的过程中,会检测该数据的大小,如果该数据较小,此时不会发送给服务端,而是将较小的包和较大的数据包合,然后一起发送给服务端。在发送下一个数据包时,系统会等待服务器对前一个数据包的响应,当收到服务器的响应后,再发送下一个数据包,这就是所谓的Nagle算法;优点很明显,节省了通信的开销,有效地改善网络传输的效率。在默认情况下是开启的。

(4)setSoLinger:其实该方法和Socket的关闭方法(
close() )是有联系的。该方法有两个参数,第一个如果设置为true,即开启该设置。第二个参数指定一个时间值(秒:0 ~ 65535,不可为负值)。该方法的作用是当你调用了Socket的close方法时,系统会去检测是否还有未发送完毕的数据,此时如果存在未发送完毕的数据,系统就会在我们指定的时间内 “努力”发送这些数据到服务器,如果在我们指定的时间内还未发送完毕,那么此时Socket将会执行关闭。如果底层的Socket实现不支持SO_LINGER都会抛出SocketException,可以通过getSoLinger方法来获取延迟关闭的时间,如果返回
-1,则表明SO_LINGER是关闭的。

(5)setReceiveBufferSize:该方法比较简单,设置输入流的缓冲大小。默认情况下,输入流的接收缓冲区是8096个字节(8K)。这个值是Java所建议的输入缓冲区的大小。缓冲值尽量不要设置的太小,否则会导致传输数据过于频繁,从而降低网络传输的效率。如果底层不支持,系统将会抛出IllegalArgumentException异常。

(6)setSendBufferSize:此方法和上面的对称,设置输出流的缓冲大小。其他特点和上面相同,不再赘述。

(7)setReuseAddress:如果你的服务程序停止后想立即重启,不等60秒,而新套接字依旧 使用同一端口,此时
SO_REUSEADDR 选项非常有用。

(8)setOOBInline:Socket类的sendUrgentData方法向服务器发送一个单字节的数据。这个单字节数据并不经过输出缓冲区,而是立即发出。

一般情况下,几个设置项我们都选择开启状态,某些情况下,还需要具体情况具体分析。

上面详细介绍了Socket的几个重要的核心方法,接下来看服务端的创建:

客户端的创建非常简单,只需要我们指定具体的端口号就行。

分析完了具体的创建过程,我们来看下Socket和ServerSocket是怎么进行通信的。

Socket采用流的形式来进行通信,OutputStream、InputStream、ObjectInputStream、ObjectOutputStream

(1)OutputStream:输出流。

(2)InputStream:输入流。

(3)ObjectInputStream:对象输入流。使用该流写入实例对象时,实例对象需要实现Serializable。

(4)ObjectOutputStream:对象输出流。使用该流写出实例对象时,实例对象需要实现Serializable。

下面看客户端发送数据给服务端:

很简单,就是流读写的基本操作,不再赘述。

看服务端接收数据并返回数据的过程:

在上面代码中我们看到,首先我们开启了接收数据的一个线程。在线程中我们无限循环的去执行accept()方法。该方法是服务端接收客户端数据的方法,返回值是客户端的Socket实例。该方法在没有接收到客户端发送过来的数据时将会一直处于阻塞状态,直到接收到客户端发送的数据才会继续向下执行,接收到客户端的Socket,继续执行流的读写操作来读取和写回数据。

一个完美的Socket通信我们就介绍完了,在实际的开发过程中,因为服务端是面向多个客户端的,即 1 - N 的关系。所以我们还需要接收到客户端发来的数据后,开启对应的线程去处理对应的逻辑任务。客户端也是一样,当接收到服务器的数据时,同样需要开启新的线程来处理服务端发来的逻辑任务。

好了,关于Socket的通信我们就简单分析到这里,如果有疑问的童靴可以和我联系一起讨论,欢迎大家拍砖!

时间: 2024-10-13 16:27:28

关于Socket的简单解析的相关文章

ngx lua模块源码简单解析

ngx lua模块源码简单解析分类: nginx 2014-07-11 11:45 2097人阅读 评论(0) 收藏 举报nginxlua数据结构架构目录(?)[+]对nginx lua模块的整个流程,原理简单解析.由于nginx lua模块相关配置,指令,API非常多,所以本文档只以content_by_lua指令举例说明. 读本文档最好配合读源码. 不适合对nginx和lua一点都不了解的人看.1.相关配置详细配置见 https://github.com/openresty/lua-ngin

用Socket来简单实现IIS服务器

刚刚接触ASP.NET编程,为了更好的屡清楚服务器的处理过程,就用Socket模拟服务器来处理请求.用Socket来模拟服务器的时候,同样是自己来封装一些对应的类文件.包括 HttpRequest.HttpResponse.HttpContext.HttpApplication.IHttpHandel.主要的执行流程是:先用Socket来创建一个简单的服务器,进行监听,当监听到请求后将请求交给处理程序去处理,应用程序中根据请求的是静态资源还是动态资源做出不同的处理.然后通过Socket对象将响应

Socket实现简单Web服务器

上一篇博客中介绍了怎样使用socket访问web服务器.关键有两个: 1)熟悉Socket编程: 2)熟悉HTTP协议. 上一篇主要是通过socket来模拟浏览器向(任何)Web服务器发送(HTTP)请求,重点在浏览器端.本篇博客则反过来讲一下怎样使用socket来实现Web服务器,怎样去接收.分析.处理最后回复来自浏览器的HTTP请求. HTTP协议是浏览器和Web服务器都需要遵守的一种通信规范,如果我们编写一个程序,正确遵守了HTTP协议,那么理论上讲,这个程序可以具备浏览器.甚至Web服务

[python网络编程]利用socket编写简单的服务器

利用socket编写简单的服务器 步骤解析 建立socket对象 这一步跟我们上次使用socket做客户端是一样的,都需要有一个socket连接 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 设置socket选项(setsockopt) 选项介绍setsockopt(set socket option),参数设置格式:setsockopt(level,optname,value) 各选项的关系:1.level:level的设定决定了op

C#中使用Socket实现简单Web服务器

原文地址:https://www.cnblogs.com/mq0036/p/6656888.html 最近有个web的小项目,但公司的电脑无法安装IIS,所以就想自己来实现个Web server服务器,原本想了下,也就是socket处理http请求,于是就在博客园中搜索了"socket实现web server",结果还真搜索到一些文章,于是从中找了几个做参考,如下: C#中使用Socket实现简单Web服务器 C#中使用Socket模拟请求Web服务器过程 C#中自己动手创建一个Web

对 cloudwu 简单的 cstring 进行简单解析

题外话 以前也用C写过字符串,主要应用的领域是,大字符串,文件读取方面.写的很粗暴,用的凑合着.那时候看见云风前辈的一个开源的 cstring 串. 当时简单观摩了一下,觉得挺好的.也没细看.过了较长一段时间,想整合一下,将大字符串和云风的cstring 短简单的串合在一起变成一种.但是自己 认真复制了一遍后发现. 1.整合不了 云风(后面都省略前辈二字,觉得云风两个字,就已经帅的不行了)简单cstring.因为处理的领域不一样. 云风的 cstring => String , 而自己写的操作文

SQLServer 原理简单解析

(1) 客户端sqlserver网络接口通过一种网络协议(可以是共享内存:简单高速,客户端和sql server在同一台计算机默认连接方式:TCP/IP:访问sql server最常用的一种协议,客户端指定ip地址和端口号连接到sql server;命名管道:命名管道和TCP/IP协议在体系结构上是类似的,是为局域网设计的,在广域网中速度会慢一些:VIA:虚拟接口适配器,是一种可以让两个系统进行高性能通信的协议,要求通信两端使用特殊的硬件和专门连接)和服务的的SNI建立了一个连接,然后通过网络协

关于Socket编写简单聊天工具的总结(原创)

这段时间再看socket编程,虽然现在是刚刚接触,但是还是忍不住想写一篇总结,来激励自己努力学习,写的不好的地方,还请大家指教啊! 下面针对一个简单的发送消息和文件的程序说说吧.   首先是服务器需要准备二个Socket和二个Thread如下: //和客户机进行通信 private Socket sckCommit; //监听客户机 private Socket sckListen; private Thread thdListen; private Thread thdCommit; 对客户机

ContextImpl简单解析

ContextImpl是对Context的一个具体实现类,关键方法如下 1 static class ServiceFetcher { 2 int mContextCacheIndex = -1; 3 /** 4 * Main entrypoint; only override if you don't need caching. 5 */ 6 public Object getService(ContextImpl ctx) { 7 ArrayList<Object> cache = ctx