Socket(套接字)通信

网络进程间通信在传输层中,基本上都是用的Socket,Cocoa中使用Socket有三种方式:

  1. Cocoa层:NSURL;Cocoa层是最上层的基于Objective-C的API,如URL访问,NSStream,Bonjour,GameKit等,大多数情况下我们常用这种API。Cocoa层是基于Core Foundation 实现的
  2. Core Foundation层:基于C语言的CFNetwork和CFNetServices;它是苹果对OS层的socket进行的简单封装,以简化编程任务。该层提供了CFNetwork和CFNetServices,其中CFNetwork又是基于CFStream和CFSocket。
  3. OS层:基于C语言的BSD socket;最底层的BSD Socket最为灵活,但抽象层次比较低,使用起来比较复杂。

Socket 起源于Unix,是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
Socket是对TCP/IP协议的封装,Socket本身不是协议,而是一个调用接口(API)通过Socket我们才能使用TCP/IP协议。

下面用BSD Socket基础接口编程实现设备间的通信:

服务器端:

socket:又称“套接字”,用于描述IP地址和端口 是一个通信链的句柄 可以用来实现不同虚拟机或不同计算机之间的通信。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的

  1. 创建Socket socket()
  2. 绑定IP地址号 bind()
  3. 监听客户端 listen()会阻塞当前线程 所以应新开辟一条线程来执行后面操作,等待连接的建立
  4. 接收客户端信息 accept();
  5. 关闭socket close()

客户端:

  1. 建立Socket
  2. 客户端不需要绑定IP 直接创建connect链接 可以自动获取自身IP,服务器端IP才需要绑定,链接过程中确定链接哪个服务器 确定服务器的IP地址 connect()
  3. 发送信息,服务器端接收信息 并接收服务器端传递过来的信息;信息的读取 send()
  4. 关闭Socket close()

客户端端口应根据服务器的端口设置,保持一致
*先关客户端socket 再关服务器socket
服务器端需绑定一个IP:bind(),而客户端不用 在connect()时由系统随机生成一个 。
socket()函数创建的socket默认是注定类型的 ,listen()函数会将传入的socket变为被动类型的,等待客户的连接要求 。

上述操作中用到的函数:

  • socket ( ) 函数:
    对应于普通文件的打开操作,并返回一个文件描述字;而socket()用于创建一个socket描述(int类型),它唯一标识一个socket,这个socket描述字跟文件描述字一样,后续操作(如bind、listen等都需要将该描述传入)都有用到它,将其作为参数进行一些读写操作 。

代码示例:

//返回的int类型值 将作为唯一的socket描述字
serverSocketId = socket(AF_INET, SOCK_STREAM, 0);
  • bind ( ) 函数:
    该函数把一个地址族中的特定地址赋给socket,例如在结构体addr中 传入IP类型AF_INET就是把一个ipv4地址和传入端口号组合,赋给socket。通用服务器在启动时会绑定一个客户端都知道的地址用于提供服务,客户可通过它连接服务器;而客户端由系统自动分配一个端口号和本机的IP地址组合,是在connect ( ) 时由系统随机生成的。
//创建地址结构体
struct sockaddr_in addr;

//初始化addr结构体
memset(&addr, 0, sizeof(addr));

//设置地址类型
addr.sin_family = AF_INET;

//设置端口号
addr.sin_port = htons(2222);

//设置ip地址    INADDR_ANY:获取当前本机正在使用的ip地址, htonl:统一成规定字节符
addr.sin_addr.s_addr = htonl(INADDR_ANY);

//绑定
int bindId = bind(serverSocketId, (struct sockaddr*)&addr, sizeof(addr));
  • listen ( ) 、connect ( ) 函数:
    如果作为一个服务器,在调用socket ( ) 、bind ( ) 之后就会调用listen ( ) 来监听这个socket,如果客户端这时调用connect ( ) 发出连接请求,服务器端就会接收到这个请求。listen函数会将socket变为被动类型,等待客户的连接请求。客户端通过调用connect函数来建立与TCP服务器的连接。
//监听   
int listenId = listen(serverSocketId, 5);

//创建服务器端addr地址
struct sockaddr_in addr;

//初始化addr
memset(&addr, 0, sizeof(addr));

//IP地址类型
addr.sin_family = AF_INET;

//设置端口号
addr.sin_port = htons(2222);

//设置指定的ip地址
inet_pton(AF_INET, "192.168.1.103", &addr.sin_addr);

//连接
int connectId = connect(clientSocketId, (struct sockaddr*)&addr,sizeof(addr));
  • accept ( ) 函数:
    TCP客户端调用connect函数之后就向TCP服务器发送了一个连接请求,TCP服务器监听到这个请求之后就会调用accept ( ) 函数接受请求,这样连接就建立完成,之后可以开始网络I/O操作,类同于普通文件de读写I/O操作。
    注意:accept函数的第一个参数为服务器的socket描述字,是服务器开始调用socket函数生成的 称为监听socket描述字;而通过accept函数返回的是已连接的socket描述字,一个服务器通常仅创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每一个由服务器进程接收的客户连接创建了一个已连接socket描述字(即accept函数返回的socket描述字),当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。
//返回值是由内核自动生成的一个全新的描述字,代表与返回客户的连接
socketNewId = accept(serverSocketId, NULL, NULL);
  • 网络 I/O 操作函数组:服务器端与客户端连接完成后,就可调用网络 I/O进行需要的操作了 主要有以下几组:
    read ( ) / write ( ) ;recv ( ) / send ( ) ;readv ( ) / writev ( ) ;recvmsg ( ) / sendmsg ( ) ;recvfrom ( ) / sendto ( )

*write函数负责从fd中读取内容,读取成功时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误。如果错误为EINTR说明读是由中断引起的,如果是ECONNREST表示网络连接出了问题。
*write函数将but中的那边有特色子节内容写入文件描述符fd,成功时返回写的字节数,失败时返回-1,并设置error变量。在网络程序中 当我们向套接字文件描述符write时有两种可能:(1)write的返回值大于0,表示write了部分或者全部的数据(2)返回的值小于0,此时出现了错误。如果错误为EINTR,表示在write的时候出现了中断错误,如果为EPIPE表示网络连接出现问题(可能对方已经关闭了连接)

我们用代码演示其中的 recv ( ) / send ( ) 函数组 :

//开辟空间
char str[1000];

//接收信息
long recvId = recv(socketNewId, &str, 1000, 0);    
char *str = "hehe";

//发送消息
long sendid = send(clientSocketId, str, sizeof(str), 0);
  • close ( ) 函数:
    在服务器与客户端建立连接之后会进行一些操作,完成操作后就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。close一个TCP socket时就把该socket标记为关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,即不能再作为read或write的第一个参数。
    注意:close操作只是使相应的socket描述字的引用计数-1,而只有当其引用计数为0时才会触发TCP客户端向服务器端向服务器发送终止连接请求。
close(socketNewId);
close(serverSocketId);

socket中TCP的三次握手建立连接:

当客户端调用connect时,触发了连接请求,向服务器发送了SYNJ包,这时connect进入阻塞状态;服务器监听到连接请求(收到SYNJ包)调用accept函数接收请求向客户端发送SYNK,ACKJ+1,这时accept进入阻塞状态;客户端收到服务器的SYNK,ACKJ+1之后,这时connect返回,并对SYNK进行确认;服务器收到ACKK+1时,accept返回,至此三次握手完毕,连接建立。客户端的connect在三次握手的第二次返回,而服务器端的accept在三次握手的第三次返回

socket中TCP的四次握手释放连接:

某个应用进程首先调用close主动关闭连接,这时TCP发生一个FIN M;另一个端接收到FIN M之后执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接受意味着应用程序在相应的连接上再也接收不到额外数据;一段时间后,接收到文件结束符的应用进程调用close关闭它的socket,这导致它的TCP也发送一个FINN;接收到这个FIN的源发送端TCP对它进行确认。这样每个方向上都有一个FIN和ACK

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 一、网络各个协议:TCP/IP、SOCKET、HTTP等 网络七层由下往上分别为物理层、数据链路层、网络层、传输层...
    杯水救车薪阅读 2,258评论 0 17
  • 1、TCP状态linux查看tcp的状态命令:1)、netstat -nat 查看TCP各个状态的数量2)、lso...
    北辰青阅读 9,398评论 0 11
  • 前言 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服...
    Chars阅读 2,972评论 2 117
  • 1)OSI与TCP/IP各层的结构与功能,都有哪些协议。 OSI分层 (7层):物理层、数据链路层、网络层、传输层...
    ldlywt阅读 2,305评论 0 26
  • 秋色 从来没有这么仔细地观察秋色。看这银杏,大部分已变金黄,...
    拙兰阅读 666评论 11 16