iOS中基于 Socket 的 C/S 结构网络通信(中)
结合上一篇的知识。接下来将介绍基于 TCP 协议的 Socket 编程。因为 Socket 须要有client和服务端,那么如今实现的是关于服务端的简单程序。服务端採用的是CFStream 类来实现的。
这个服务端是把Xcode中的 Command Line Tool 来作为服务端的;当然,你也能够把 iPhone 作为服务端。可是要利用其它的框架,比方 AsyncSocket (https://github.com/roustem/AsyncSocket)
,里面有分为 UDP 和 TCP 实现的 Socket。源程序里也有很多关于数据流的操作,能够作为深入理解来用,当然也是比較复杂的。
以下来看一下简单实现的 TCP 服务端程序:(TCPServer.m)
<pre name="code" class="objc">#import <CoreFoundation/CoreFoundation.h>
#include <sys/socket.h>
#include <netinet/in.h> #define PORT 8734 void AcceptCallBack(CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *); void WriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType, void *); void ReadStreamClientCallBack (CFReadStreamRef stream, CFStreamEventType eventType,void *); int main(int argc, const char * argv[])
{
/* 定义一个Server Socket引用 */
CFSocketRef sserver; /* 创建socket context */
CFSocketContext CTX = { 0, NULL, NULL, NULL, NULL }; /* 创建server socket TCP IPv4 设置回调函数 */
sserver = CFSocketCreate(NULL, PF_INET, SOCK_STREAM, IPPROTO_TCP,
kCFSocketAcceptCallBack, (CFSocketCallBack)AcceptCallBack, &CTX);
if (sserver == NULL)
return -1; /* 设置是否又一次绑定标志 */
int yes = 1;
/* 设置socket属性 SOL_SOCKET是设置tcp SO_REUSEADDR是又一次绑定。yes 是否又一次绑定*/
setsockopt(CFSocketGetNative(sserver), SOL_SOCKET, SO_REUSEADDR,
(void *)&yes, sizeof(yes)); /* 设置端口和地址 */
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr)); //memset函数对指定的地址进行内存拷贝
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET; //AF_INET是设置 IPv4
addr.sin_port = htons(PORT); //htons函数 无符号短整型数转换成“网络字节序”
addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY有内核分配。htonl函数 无符号长整型数转换成“网络字节序” /* 从指定字节缓冲区复制。一个不可变的CFData对象*/
CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8*)&addr, sizeof(addr)); /* 设置Socket*/
if (CFSocketSetAddress(sserver, (CFDataRef)address) != kCFSocketSuccess) {
fprintf(stderr, "Socket绑定失败\n");
CFRelease(sserver);
return -1;
} /* 创建一个Run Loop Socket源 */
CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sserver, 0);
/* Socket源加入到Run Loop中 */
CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
CFRelease(sourceRef); printf("Socket listening on port %d\n", PORT);
/* 执行Loop */
CFRunLoopRun(); } /* 接收client请求后,回调函数 */
void AcceptCallBack(
CFSocketRef socket,
CFSocketCallBackType type,
CFDataRef address,
const void *data,
void *info)
{
CFReadStreamRef readStream = NULL;
CFWriteStreamRef writeStream = NULL; /* data 參数涵义是,假设是kCFSocketAcceptCallBack类型,data是CFSocketNativeHandle类型的指针 */
CFSocketNativeHandle sock = *(CFSocketNativeHandle *) data; /* 创建读写Socket流 */
CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock,
&readStream, &writeStream); if (!readStream || !writeStream) {
close(sock);
fprintf(stderr, "CFStreamCreatePairWithSocket() 失败\n");
return;
} CFStreamClientContext streamCtxt = {0, NULL, NULL, NULL, NULL};
// 注冊两种回调函数
CFReadStreamSetClient(readStream, kCFStreamEventHasBytesAvailable, ReadStreamClientCallBack, &streamCtxt);
CFWriteStreamSetClient(writeStream, kCFStreamEventCanAcceptBytes, WriteStreamClientCallBack, &streamCtxt); //加入到循环其中
CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes); CFReadStreamOpen(readStream);
CFWriteStreamOpen(writeStream); } /* 读取流操作 client有数据过来时候调用 */
void ReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void* clientCallBackInfo){ UInt8 buff[255];
CFReadStreamRef inputStream = stream; if(NULL != inputStream)
{
CFReadStreamRead(stream, buff, 255);
printf("接受到数据:%s\n",buff);
CFReadStreamClose(inputStream);
CFReadStreamUnscheduleFromRunLoop(inputStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
inputStream = NULL;
}
} /* 写入流操作 client在读取数据时候调用 */
void WriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType, void* clientCallBackInfo)
{
CFWriteStreamRef outputStream = stream;
//输出
UInt8 buff[] = "你好,client!"; //向client发送的信息
if(NULL != outputStream)
{
CFWriteStreamWrite(outputStream, buff, strlen((const char*)buff)+1);
//关闭输出流
CFWriteStreamClose(outputStream);
CFWriteStreamUnscheduleFromRunLoop(outputStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
outputStream = NULL;
}
}
此段程序仅仅涉及比較简单的数据流操作,具体的数据流操作请參考 AsyncSocket 的源代码;至此,那么一个服务端就已经实现了。
未完待续......
iOS中基于 Socket 的 C/S 结构网络通信(中)的更多相关文章
- 34、Android中基于Socket的网络通信(一)
Socket又称”套接字”,应用程序通常通过”套接字”向网络发出请求或者应答网络请求. 在java中,Socket和ServerSocket类库位于java.net包中,ServerSocket用于服 ...
- Android中基于Socket的网络通信
1. Socket介绍 2. ServerSocket的建立与使用 3. 使用ServerSocket建立聊天服务器-1 4. 使用ServerSocket建立聊天服务器-2 5. 在Android中 ...
- iOS:基于Socket的第三方框架CocoaAsyncSocket的使用
CocoaAsyncSocket无疑是目前封装得最完善的Socket库了:支持异步TCP/UDP,支持GCD,Objective-C接口封装,同时还有日志跟踪功能,使用此日志跟踪,程序员可以很方便的进 ...
- C#中使用Socket请求Web服务器过程
最开始我们需要明白一件事情,因为这是这篇文章的前提: HTTP协议只是一个应用层协议,它底层是通过TCP进行传输数据的.因此,浏览器访问Web服务器的过程必须先有“连接建立”的发生. 而有人或许会问: ...
- 手写简易版RPC框架基于Socket
什么是RPC框架? RPC就是远程调用过程,实现各个服务间的通信,像调用本地服务一样. RPC有什么优点? - 提高服务的拓展性,解耦.- 开发人员可以针对模块开发,互不影响.- 提升系统的可维护性及 ...
- 在iOS中获取UIView的所有层级结构 相关
在iOS中获取UIView的所有层级结构 应用场景 在实际 iOS 开发中,很多时候都需要知道某个 UI 控件中包含哪些子控件,并且分清楚它们的层级结构和自个的 frame 以及 bounds ,以便 ...
- 基于 socket.io, 简单实现多平台类似你猜我画 socket 数据传输
一.前言 socket.io 实现了实时双向的基于事件的通讯机制,是基于 webSocket 的封装,但它不仅仅包括 webSocket,还对轮询(Polling)机制以及其它的实时通信方式封装成了通 ...
- 基于Socket的低层次Java网络编程
Socket通讯 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket是TCP/IP协议的一个十分流 ...
- iOS之基于FreeStreamer的简单音乐播放器(模仿QQ音乐)
代码地址如下:http://www.demodashi.com/demo/11944.html 天道酬勤 前言 作为一名iOS开发者,每当使用APP的时候,总难免会情不自禁的去想想,这个怎么做的?该怎 ...
随机推荐
- RPC通信框架——RCF介绍
现有的软件中用了大量的COM接口,导致无法跨平台,当然由于与Windows结合的太紧密,还有很多无法跨平台的地方.那么为了实现跨平台,支持Linux系统,以及后续的分布式,首要任务是去除COM接口. ...
- JFreeChart之堆叠柱形图(StackedBar)
JFreeChart之堆叠柱形图(StackedBar) JAVA JFreeChart 最近的项目使用有个功能需要使用到堆叠柱形图,看了项目以前的代码实现没有想要的结果.所以自己就先到官网下载了 D ...
- PCB LDI 实现周期自动更新 实现思路
一.基本思路整理如下: 二.封周期启动程序C#代码(部份代码) /// <summary> /// 单个生产型号 更新周期 /// </summary> /// <par ...
- JS——事件详情(鼠标事件:clientX、clientY的用法)
鼠标位置 >可视区位置:clientX.clientY 跟着鼠标移动的div案例 代码如下图: 这个案例,运用到前一篇文章中的event事件来处理.获取div的left和top值,当鼠标移动 ...
- 微信js sdk上传多张图片
微信js sdk上传多张图片,微信上传多张图片 该案例已tp3.2商城为例 直接上代码: php代码: public function ind(){ $appid="111111111111 ...
- Redis(三)-Ubuntu下安装
Ubuntu 下安装 在 Ubuntu 系统安装 Redi 可以使用以下命令: $sudo apt-get update $sudo apt-get install redis-server 启动 R ...
- 【区间DP】释放囚犯
貌似和石子合并差不多 可能是我见的题太少了,所以都差不多 OK 算法分析 首先不难看出这是一道区间DP,那么,按照本蒟蒻的意思 区间DP==三个循环 for(int len=2;len<=n;l ...
- python之路——常用模块
阅读目录 认识模块 什么是模块 模块的导入和使用 常用模块一 collections模块 时间模块 random模块 os模块 sys模块 序列化模块 re模块 常用模块二 hashlib模块 con ...
- C99新增内容之复合文字(compound literal)
前言: 最近在复习C,发现了一些新东西,例如:变长数组,复合文字,指针的兼容性等.今天先简单谈一下复合文字. 正文: 假如需要向带有一个int参量的函数传递一个值,您可以传递一个int变量,也可以传递 ...
- Beta冲刺-星期三
这个作业属于哪个课程 <课程的链接> 这个作业要求在哪里 <作业要求的链接> 团队名称 Three cobblers 这个作业的目标 剩余任务预估,分配 ...