一、什么是Socket通信:

Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换。这个双向连路的一端称为socket。socket通常用来实现客户方和服务方的连接。socket是TCP/IP协议的一个十分流行的编程接口。一个socket由一个IP地址和一个端口号唯一确定。TCP/IP协议的传输层又有两种协议:TCP(传输控制协议)和UDP(用户数据报协议)。TCP是基于连接的,而UDP是无连接的;TCP对系统资源的要求较多,而UDP少;TCP保证数据的正确性而UDP可能丢包;TCP保证数据顺序而UDP不保证。

二、Socket编程:

2.1  服务器端监听某个端口是否有连接请求。服务器端程序处于堵塞状态,直到客户端像服务器端发出连接请求,服务器端接受请求才能向下运行。一旦连接建立起来,通过socket可以获得输入输出流对象。借助于输入输出流对象就可以实现与客户端的通信,最后不要忘记关闭socket和释放一些资源(包括关闭输入/输出流)。

2.2  客户端流程是先指定要通信的服务器IP地址、端口和采用的传输协议(TCP/UDP),向服务器发出连接请求,服务器有应答请求之后,就会建立连接。之后与服务器端一样。

三、 iOS网络编程的层次结构:

(1)Foundation:提供了 NSStream,Bonjour,GameKit,基于Core Foundation框架实现。

(2)Core Foundation:提供了CFStream,CFNetServices,面向C语言实现。

(3)BSD Socket :面向C实现,完全使用C编写。

四、实例:NSStream&CFStream实现TCP Socket服务器端

#import <CoreFoundation/CoreFoundation.h>
#include <sys/socket.h>
#include <netinet/in.h> #define PORT 8080 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 = { , 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 -; /* 设置是否重新绑定标志 */
int yes = ;
/* 设置socket属性 SOL_SOCKET是设置tcp SO_REUSEADDR是重新绑定,yes 是否重新绑定*/
setsockopt(CFSocketGetNative(sserver), SOL_SOCKET, SO_REUSEADDR,
(void *)&yes, sizeof(yes)); /* 设置端口和地址 */
struct sockaddr_in addr;
memset(&addr, , 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 -;
} /* 创建一个Run Loop Socket源 */
CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sserver, );
/* Socket源添加到Run Loop中 */
CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
CFRelease(sourceRef); printf("Socket listening on port %d\n", PORT);
/* 运行Loop */
CFRunLoopRun(); } /* 接收客户端请求后,回调函数 */
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 = {, 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); } /* 读取流操作 客户端有数据过来时候调用 */
void ReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void* clientCallBackInfo){ UInt8 buff[];
CFReadStreamRef inputStream = stream; if(NULL != inputStream)
{
CFReadStreamRead(stream, buff, );
printf("接受到数据:%s\n",buff);
CFReadStreamClose(inputStream);
CFReadStreamUnscheduleFromRunLoop(inputStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
inputStream = NULL;
}
} /* 写入流操作 客户端在读取数据时候调用 */
void WriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType, void* clientCallBackInfo)
{
CFWriteStreamRef outputStream = stream;
//输出
UInt8 buff[] = "Hello Client!";
if(NULL != outputStream)
{
CFWriteStreamWrite(outputStream, buff, strlen((const char*)buff)+);
//关闭输出流
CFWriteStreamClose(outputStream);
CFWriteStreamUnscheduleFromRunLoop(outputStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
outputStream = NULL;
}
}

NSStream&CFSteam实现TCP Socket客户端

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
[super viewDidLoad];
} - (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
} - (void)initNetworkCommunication
{ CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"192.168.1.112", PORT, &readStream, &writeStream); _inputStream = (__bridge_transfer NSInputStream *)readStream;
_outputStream = (__bridge_transfer NSOutputStream
*)writeStream;
[_inputStream setDelegate:self];
[_outputStream setDelegate:self];
[_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[_inputStream open];
[_outputStream open]; }
-(void)close
{
[_outputStream close];
[_outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream setDelegate:nil];
[_inputStream close];
[_inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_inputStream setDelegate:nil];
} - (IBAction)sendData:(id)sender {
flag = ;
[self initNetworkCommunication]; } - (IBAction)receiveData:(id)sender {
flag = ;
[self initNetworkCommunication]; } -(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSString *event;
switch (streamEvent) {
case NSStreamEventNone:
event = @"NSStreamEventNone";
break;
case NSStreamEventOpenCompleted:
event = @"NSStreamEventOpenCompleted";
break;
case NSStreamEventHasBytesAvailable:
event = @"NSStreamEventHasBytesAvailable";
if (flag == && theStream == _inputStream) {
NSMutableData *input = [[NSMutableData alloc] init];
uint8_t buffer[];
NSInteger len;
while([_inputStream hasBytesAvailable])
{
len = [_inputStream read:buffer maxLength:sizeof(buffer)];
if (len > )
{
[input appendBytes:buffer length:len];
}
}
NSString *resultstring = [[NSString alloc] initWithData:input encoding:NSUTF8StringEncoding];
NSLog(@"接收:%@",resultstring);
_message.text = resultstring;
}
break;
case NSStreamEventHasSpaceAvailable:
event = @"NSStreamEventHasSpaceAvailable";
if (flag == && theStream == _outputStream) {
//输出
UInt8 buff[] = "Hello Server!";
[_outputStream write:buff maxLength: strlen((const char*)buff)+];
//必须关闭输出流否则,服务器端一直读取不会停止,
_tipMessage.text = @"发送成功!";
[_outputStream close];
}
break;
case NSStreamEventErrorOccurred:
event = @"NSStreamEventErrorOccurred";
[self close];
break;
case NSStreamEventEndEncountered:
event = @"NSStreamEventEndEncountered";
NSLog(@"Error:%ld:%@",[[theStream streamError] code], [[theStream streamError] localizedDescription]);
break;
default:
[self close];
event = @"Unknown";
break;
}
NSLog(@"event------%@",event);
}

实际上,socket编程是一种网络编程的标准,客户端和服务器端可以不受编程语言的限制完全自由的通信。客户端可以是oc编写的iOS程序,服务端可以是java编写的程序,通信双方定义好数据交互格式就可以了。

五、最后说一下Socket连接与http连接

由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。

而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。

注:源码参考自《iOS网络编程与云端应用最佳实践》

iOS网络编程笔记——Socket编程的更多相关文章

  1. 网络协议 11 - Socket 编程(下):眼见为实耳听为虚

    系列文章传送门: 网络协议 1 - 概述 网络协议 2 - IP 是怎么来,又是怎么没的? 网络协议 3 - 从物理层到 MAC 层 网络协议 4 - 交换机与 VLAN:办公室太复杂,我要回学校 网 ...

  2. [深入浅出Cocoa]iOS网络编程之Socket

    http://blog.csdn.net/kesalin/article/details/8798039 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   [深入浅出Co ...

  3. 第九章:Python高级编程-Python socket编程

    第九章:Python高级编程-Python socket编程 Python3高级核心技术97讲 笔记 9.1 弄懂HTTP.Socket.TCP这几个概念 Socket为我们封装好了协议 9.2 cl ...

  4. 多线程编程以及socket编程_Linux程序设计4chapter15

    看了Linux程序设计4中文版,学习了多线程编程和socket编程.本文的程序参考自Linux程序设计4的第15章. 设计了一个客户端程序,一个服务端程序.使用TCP协议进行数据传输. 客户端进程创建 ...

  5. iOS项目开发之Socket编程

    有一段时间没有认真总结和写博客了 前段时间找工作.进入工作阶段.比较少静下来认真总结,现在静下心来总结一下最近的一些心得 前言 AsyncSocket介绍 AsyncSocket详解 AsyncSoc ...

  6. 关于网络协议和socket编程基本概念

    TCP协议可以说已经是IT人耳熟能详的协议,最近在学习socket网络编程时后重新温习一下这个协议,针对一些问题做了一些总结,很多理解可能还不是很准确. 1. 协议是什么?所谓的各种网络协议无非是一种 ...

  7. 网络协议 10 - Socket 编程(上):实践是检验真理的唯一标准

    系列文章传送门: 网络协议 1 - 概述 网络协议 2 - IP 是怎么来,又是怎么没的? 网络协议 3 - 从物理层到 MAC 层 网络协议 4 - 交换机与 VLAN:办公室太复杂,我要回学校 网 ...

  8. java网络编程之Socket编程

    概念 网络编程分为BIO(传统IO).NIO.AIO.Socket编程属于BIO这种传统IO. InetAddress java.net.InetAddress是JAVA中管理IP地址的类,常用 pu ...

  9. C#网络编程:Socket编程

    套接字简介:套接字最早是Unix的,window是借鉴过来的.TCP/IP协议族提供三种套接字:流式.数据报式.原始套接字.其中原始套接字允许对底层协议直接访问,一般用于检验新协议或者新设备问题,很少 ...

随机推荐

  1. jquery 全选 全不选 事件绑定

    <td width="82%" colspan="3"><input type="checkbox" id="a ...

  2. 如何:使用 Visual Basic 编写基于 Unity3D 的计算器

    随着 .NET 全平台战略的推进,微软正在让以 C# 为先锋的 .NET 拥有跨平台特性.这个过程中一直有人想知道其它 .NET 语言对跨平台的支持有什么改进,熟悉 C# 但是喜欢用 VB 的我也不例 ...

  3. spring-dwr注解整合

    注解配置 1.web.xml 只需将DwrServlet换为DwrSpringServlet(包名不同) 2.dwr类 3.applicationContext.xml 4.annotationCon ...

  4. LCD驱动移植在在mini2440(linux2.6.29)和FS4412(linux3.14.78)上实现对比(deep dive)

    1.Linux帧缓冲子系统 帧缓冲(FrameBuffer)是Linux为显示设备提供的一个接口,用户可以将帧缓冲看成是显示内存的一种映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作 ...

  5. 深圳尚学堂:Swift中的“!”和“?”

    Swift中的"!"和"?"Swift,苹果于2014年WWDC发布的新开发语言,用于搭建基于苹果平台的应用程序.Swift是一款易学易用的编程语言,而且它还是 ...

  6. bootstrap table编辑操作的时候 在模态框里加载iframe页面(加载的页面是在另一个页面做编辑)的时候如何关闭模态框和刷新table

    //关闭模态框                             window.parent.$('#myModal').modal('hide'); //修改成功后刷新table表格      ...

  7. Zigbee折腾之旅:(一)CC2530最小系统

    最近在倒腾Zigbee,准备参加物联网全国大赛,学校有给我们发Zigbee开发板,但是对于喜欢折腾的我来说,用开发板还是不过瘾,起码也得知道怎么去画一块板子.于是乎,在百度一番后就有了下面这篇文章. ...

  8. Ajax跨域实现淘宝/百度搜索下拉提示效果

    最近学到Ajax,觉得自己对与前后端的数据交互有了一个基本的了解.下面是Ajax应用到淘宝/百度的搜索功能的一个简单的小实例,就是输入一个词,下拉框中自动显示匹配的内容:

  9. UCOSII时间任务块

    转:http://blog.csdn.net/wchp314/article/details/5416476 uCOS-II的任务控制块 标签:  uCOS-II  2009-12-01 14:45 ...

  10. Javascript高级程序设计——语法、关键字、保留字、变量、数据类型

    1.了解基本语法,JS大小写区分.注释风格.什么是严格模式等. 2.知道ES3和ES5的关键字和保留字大概有哪些,如果使用关键字会报什么错,使用保留字决定于特定浏览器引擎. 3.全局变量和局部变量的定 ...