日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

浅学socket及iOS中的AsyncSocket框架

發(fā)布時(shí)間:2023/12/20 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅学socket及iOS中的AsyncSocket框架 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

淺學(xué)socket及iOS中的AsyncSocket框架

Socket介紹:http://blog.csdn.net/xiaoweige207/article/details/6211577

Socket是TCP/IP協(xié)議應(yīng)用程序的變成接口,網(wǎng)絡(luò)層的“ip地址”可以唯一標(biāo)識(shí)網(wǎng)絡(luò)中的主機(jī),而傳輸層的“協(xié)議+端口”可以唯一標(biāo)識(shí)主機(jī)中的應(yīng)用程序(進(jìn)程)。這樣利用三元組(ip地址,協(xié)議,端口)就可以標(biāo)識(shí)網(wǎng)絡(luò)的進(jìn)程了,網(wǎng)絡(luò)中的進(jìn)程通信就可以利用這個(gè)標(biāo)志與其它進(jìn)程進(jìn)行交互。使用TCP/IP協(xié)議的應(yīng)用程序通常采用應(yīng)用編程接口:UNIX? BSD的套接字(socket)和UNIX System V的TLI(已經(jīng)被淘汰),來實(shí)現(xiàn)網(wǎng)絡(luò)進(jìn)程之間的通信。

我們可以這樣理解,因?yàn)閟ocket起源于Unix,而Unix和Linux基本操作模式是“打開(Open)à讀寫(Write/read)à關(guān)閉(Close)”,所以socket也可以理解為就是這種模式的一種實(shí)現(xiàn),socket中一些函數(shù)就是對(duì)其進(jìn)行(讀/寫IO、打開和關(guān)閉)操作的。

?

Socket基本操作

1、socket( )函數(shù):intsocket(int domain,int type,int protocol);

socket函數(shù)對(duì)應(yīng)于普通文件的打開操作,普通文件的打開操作返回一個(gè)文件的描述字,socket函數(shù)就用于創(chuàng)建一個(gè)socket的描述符。

參數(shù):

int domainà即協(xié)議域,又稱為協(xié)議族(family);

常用協(xié)議:常用的協(xié)議族有,AF_INET、AF_INET6、AF_LOCAL(或稱AF_UNIX,Unix域socket)、AF_ROUTE等等。協(xié)議族決定了socket的地址類型,在通信中必須采用對(duì)應(yīng)的地址,如AF_INET決定了要用ipv4地址(32位的)與端口號(hào)(16位的)的組合、AF_UNIX決定了要用一個(gè)絕對(duì)路徑名作為地址。

int typeà指定socket類型。

常用類型:指定socket類型。常用的socket類型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等

int protocolà指定協(xié)議。

常用協(xié)議:IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它們分別對(duì)應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議、STCP傳輸協(xié)議、TIPC傳輸協(xié)議。

當(dāng)我們調(diào)用socket創(chuàng)建一個(gè)socket時(shí),返回的socket描述字放在協(xié)議簇family中,在協(xié)議簇中的描述字沒有一個(gè)具體的地址,此時(shí)就要通過blind()函數(shù)給它賦值地址,或者調(diào)用conncet()、listen()讓系統(tǒng)自動(dòng)分配端口;

2、bind( )函數(shù):int bind(intsockfd, const struct sockaddr *addr, socklen_t addrlen),bind()函數(shù)的作用就是把一個(gè)地址族中的特定地址賦給socket;

參數(shù):

int sockfdà即scoket描述字,它通過socket()函數(shù)創(chuàng)建,唯一標(biāo)示一個(gè)socket.

const struct sockaddr *addrà一個(gè)const struct sockaddr *指針指向要綁定給sockfd的協(xié)議地址,這個(gè)地址結(jié)構(gòu)根據(jù)地址創(chuàng)建socket是地址協(xié)議族的不同而不同

ipv4對(duì)應(yīng)的是:?

struct sockaddr_in {????

sa_family_t??? sin_family; /* address family: AF_INET*/????

in_port_t????? sin_port;?? /* port in network byte order */????

struct in_addr sin_addr;?? /* internet address */

};

?/*Internet address. */

struct in_addr {????

uint32_t?????? s_addr;???? /* address in network byte order */

};

ipv6對(duì)應(yīng)的是:?

struct sockaddr_in6 {?????

sa_family_t???? sin6_family;?? /* AF_INET6 */?????

in_port_t?????? sin6_port;???? /* port number */?????

uint32_t??????? sin6_flowinfo; /* IPv6 flow information*/?????

struct in6_addr sin6_addr;???? /* IPv6 address */?????

uint32_t??????? sin6_scope_id; /* Scope ID (new in 2.4)*/?

};?

struct in6_addr {?????

unsigned char?? s6_addr[16];?? /* IPv6 address */

?};

Unix域?qū)?yīng)的是:?

#define UNIX_PATH_MAX??? 108?struct sockaddr_un {????

?sa_family_t sun_family;?????????????? /* AF_UNIX */????

?char?sun_path[UNIX_PATH_MAX];? /* pathname */? };

socklen_t addrlenà對(duì)應(yīng)的地址的長(zhǎng)度

關(guān)于網(wǎng)絡(luò)字節(jié)序與主機(jī)字節(jié)序的詳細(xì)分析:

http://blog.csdn.net/ernest201210/article/details/8690686

http://blog.csdn.net/icedmilk/article/details/5336296

http://bbs.csdn.net/topics/60375114

服務(wù)器在調(diào)用scoket()、bind()之后就會(huì)調(diào)用listen()來監(jiān)聽這個(gè)socket,如果這是客戶端調(diào)用connect()發(fā)送出請(qǐng)求連接,服務(wù)器就會(huì)接收到請(qǐng)求

3、listen( ):int listen(int sockfd , int backlog);

參數(shù):

int sockfdà即要監(jiān)聽的socket描述字;

int backlogà相應(yīng)socket可以排隊(duì)的最大鏈接個(gè)數(shù)

4、connect( )函數(shù):intconnect(int sockfd , const struct sockaddr * addr ,socklen_t addrlen);

參數(shù):

int sockfdà客戶端的socket描述字;

const struct sockaddr * addr à服務(wù)器的socket地址

socklen_t addrlenàsocket地址的長(zhǎng)度

當(dāng)服務(wù)器開始監(jiān)聽,客戶端發(fā)送連接請(qǐng)求后,TCP服務(wù)器監(jiān)聽到請(qǐng)求就會(huì)調(diào)用accept()函數(shù)接收請(qǐng)求,網(wǎng)絡(luò)連接成功。

5、accept( )函數(shù):int accept(int sockfd, struct sockaddr *addr, socklen _t *addrlen);

參數(shù):

int sockfdà服務(wù)器的socket描述字;

struct sockaddr * addrà指向struct sockaddr * 的指針,用于返回客戶端的協(xié)議地址

socklen_t * addrlenà協(xié)議地址的長(zhǎng)度

【注】1、accept的第一個(gè)描述字參數(shù)是服務(wù)器開始調(diào)用socket就生成的一個(gè)監(jiān)聽描述字,當(dāng)accept成功建立鏈接后就返回一個(gè)已鏈接的scoket描述字,當(dāng)服務(wù)器完成服務(wù)后相應(yīng)的socket描述字就會(huì)被自動(dòng)關(guān)閉。

2、服務(wù)器通常只創(chuàng)建一個(gè)監(jiān)聽socket描述字,它在服務(wù)器的生命周期中一直存在

?

6、read( )、write( )等函數(shù)

網(wǎng)絡(luò)I/O操作有下面幾組:

read( )/write( )

recv( )/send( )

readv( )/writev( )

recvmsg( )/sendmsg( )(推薦使用)

recvfrom( )/sendto( )

這兩個(gè)函數(shù)都是通用的I/O函數(shù),可以把上面的其他函數(shù)替換成這兩個(gè)函數(shù)

它們的聲明如下:

??????#include <unistd.h>

??????ssize_t read(int fd, void *buf, size_t count);

??????ssize_t write(int fd, const void *buf, size_t count);

??????#include <sys/types.h>

??????#include <sys/socket.h>

??????ssize_t send(int sockfd, const void *buf, size_t len, int flags);

??????ssize_t recv(int sockfd, void *buf, size_t len, int flags);

??????ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

????????????????????? const struct sockaddr*dest_addr, socklen_t addrlen);

??????ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

??????????????????????? struct sockaddr*src_addr, socklen_t *addrlen);

??????ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

??????ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

7、close( )函數(shù):int close(int fd);

close一個(gè)TCP socket的缺省行為時(shí)把該socket標(biāo)記為關(guān)閉,然后立刻返回到調(diào)用進(jìn)程。該描述字不能再由調(diào)用進(jìn)程使用,也就是說不能再作為read或write的第一個(gè)參數(shù)。

【注】close操作只是使用相應(yīng)scoket描述字的引用計(jì)數(shù)-1,只有當(dāng)引用計(jì)數(shù)為0的時(shí)候,才會(huì)觸發(fā)TCP客戶端向服務(wù)器發(fā)送終止連接請(qǐng)求。

【重點(diǎn)】scoket中的TCP三次握手

TCP建立連接要進(jìn)行“三次握手”,即交換三個(gè)分組,流程:

1、客戶端向服務(wù)器端發(fā)送一個(gè)SYN J(例如:客戶向一個(gè)中間人發(fā)送請(qǐng)求,告訴他去蘋果手機(jī)店找老板拿一部iPhone6,客戶已經(jīng)付款,SYN J就是取貨的憑證,中間人拿著憑證去到蘋果手機(jī)店給老板看),第一次握手;

2、服務(wù)器向客戶端響應(yīng)一個(gè)SYN K,并對(duì)SYN J進(jìn)行確認(rèn)ACK J+1(手機(jī)店老板看到憑證后告訴中間人這個(gè)憑證我收到了,但是由于手機(jī)數(shù)量有限,價(jià)值較高,為了確保安全并且客戶收到的是自己訂購的那部手機(jī),需要進(jìn)行最后確認(rèn),手機(jī)店老板再交給中間人一個(gè)憑證,讓他帶回去給客戶確認(rèn),此時(shí)手機(jī)店老板已經(jīng)做好準(zhǔn)備發(fā)貨給客戶),第二次握手;

3、客戶端在向服務(wù)器發(fā)送一個(gè)確認(rèn)ACK K+1(客戶收到確認(rèn)憑證,經(jīng)過確認(rèn)無誤后就給老板發(fā)送一個(gè)確認(rèn)信息,老板收到信息后立刻把手機(jī)發(fā)給客戶),第三次握手;

?

【重點(diǎn)】socket中TCP的四次揮手釋放連接詳解:

1、某個(gè)應(yīng)用進(jìn)程首先調(diào)用close主動(dòng)關(guān)閉連接,這時(shí)TCP發(fā)送一個(gè)FIN M(延續(xù)上面的例子,客戶收到手機(jī)以后,又找到那個(gè)中間人帶著一張憑證FIN M去手機(jī)店告訴老板手機(jī)已經(jīng)到貨,需要關(guān)閉交易)第一次揮手;

2、另一端接收到FIN M之后,執(zhí)行被動(dòng)關(guān)閉,對(duì)這個(gè)FIN進(jìn)行確認(rèn)。它的接受也作為文件結(jié)束符傳遞給應(yīng)用進(jìn)程,因?yàn)镕IN的接受意味著應(yīng)用進(jìn)程在相應(yīng)的連接上再也接收不到額外數(shù)據(jù)(老板收到FIN M的憑證,知道手機(jī)已經(jīng)到貨,將對(duì)FIN進(jìn)行確認(rèn)看客戶是否真的收到手機(jī),是否可以關(guān)閉交易,ACK M+1),第二次揮手;

3、一段時(shí)間后,接收到文件結(jié)束符的應(yīng)用進(jìn)程調(diào)用close關(guān)閉它的socket。這導(dǎo)致它的TCP也發(fā)送一個(gè)FIN N(老板經(jīng)確認(rèn)客戶確實(shí)已經(jīng)收到手機(jī)后,主動(dòng)向執(zhí)行本次操作的應(yīng)用發(fā)送close消息,告訴中間人交易可以關(guān)閉),第三次揮手;

4、接收到這個(gè)FIN的源發(fā)送端TCP對(duì)它進(jìn)行確認(rèn)(中間人為了確保兩邊的交易順利關(guān)閉,還需要再次到客戶那里讓客戶確定一下,等到客戶確認(rèn)交易確實(shí)已經(jīng)執(zhí)行結(jié)束后,中間人得任務(wù)也就完成了,本次通訊結(jié)束),第四次揮手;

?

通過上面的簡(jiǎn)單學(xué)習(xí)可以初步了解socket的主要函數(shù)、啟動(dòng)、連接、關(guān)閉和通信流程,對(duì)于深入的研究socket網(wǎng)上還有很多博客可以提供學(xué)習(xí),例如:http://tony98889.blog.163.com/blog/static/114618632008919195827/

http://www.cnblogs.com/Jason-Damon/archive/2013/04/18/3029385.html

http://blog.csdn.net/wuqiuming2008/article/details/6776264

?

AsyncSocket:

接下來要針對(duì)iOS編程中所使用到的AsyncSocket框架做基礎(chǔ)的探究。

AsyncSocket官方文檔地址:

https://github.com/robbiehanson/CocoaAsyncSocket/wiki/Reference_GCDAsyncSocket#isConnected

對(duì)于網(wǎng)絡(luò)通信,蘋果公司的標(biāo)準(zhǔn)推薦是CFNetworkC庫,但相對(duì)編程會(huì)比較繁瑣,同其他平臺(tái)一樣,蘋果也有一套socket(套接字)的開源類庫cocoa AsyncSocket用來簡(jiǎn)化CFNetwork C的操作。

官方網(wǎng)站:http://code.google.com/p/cocoaasyncsocket/

框架使用方法:

1、在項(xiàng)目中引入AsyncSocket庫,下載框架源代碼,把框架源碼導(dǎo)入到項(xiàng)目中(只需要添加RunLoop目錄中的AsyncSocket.h,AsyncSocket.m, AsyncUdpSocket.h, AsyncUdpSocket.m四個(gè)文件)。

2、在項(xiàng)目中添加CFNetwork框架。

3、在UIViewController頭文件中定義AsyncSocket對(duì)象:#import”AsyncSocket.h”

{

??? UITextField??? * textField;

??? AsyncSocket * asyncSocket;

}

宏定義IP、端口號(hào):

#defineSRV_CONNECTED 0

#defineSRV_CONNECT_SUC 1

#define SRV_CONNECT_FAIL2

#defineHOST_IP @"192.168.110.1"

#defineHOST_PORT 8080

4、在需要連接的地方使用connectToHost連接服務(wù)器:

??asyncSocket = [[AsyncSocket alloc] initWithDelegate:self];

initWithDelegate的參數(shù)必須是self,這個(gè)對(duì)象指針中的各個(gè)socket相應(yīng)都被AsyncSocket相應(yīng)。

判斷服務(wù)器接口IP和端口號(hào):(寫在viewDidLoad里面)

if(![asyncSocketconnectToHost:@"127.0.0.1" onPort:8888 error:&err])?

{?

?//[_asyncSocket connectToHost:hostonPort:nPort error:&error];?

[_asyncSocketconnectToHost:host onPort:nPort withTimeout:2 error:&error];? (建議使用)

???????NSLog(@"Error: %@", err);?

}

(IP和端口號(hào)寫在宏定義里,這里做一個(gè)超時(shí)響應(yīng),連接服務(wù)器有一個(gè)超時(shí)可以設(shè)置,超時(shí)后調(diào)用)

?

5、增加socket相應(yīng)事件,delegate會(huì)把當(dāng)前對(duì)象傳遞過去,只要在當(dāng)前對(duì)象實(shí)現(xiàn)相應(yīng)方法即可;

(1)建立連接:

-(void)onSocket:(AsyncSocket*)sock didConnectToHost:(NSString *)host port:(UInt16)port?

{?

??? NSLog(@"onScoket:%p ?did ?connecte ?to ?host:%@ ?on port:%d",sock,host,port);?

??? [sock readDataWithTimeout:1 tag:0];?

}

(2)讀取數(shù)據(jù)?

-(void)onSocket:(AsyncSocket*)sock didReadData:(NSData *)data withTag:(long)tag?

{?

??? NSString *aStr=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];?

??? NSLog(@"aStr==%@",aStr);?

??? [aStr release];?

??? NSData *aData=[@"Hi there"dataUsingEncoding:NSUTF8StringEncoding];?

??? [sock writeData:aData withTimeout:-1tag:1];?

??? [sock readDataWithTimeout:1 tag:0];?

}?

(3)是否加密?

-(void)onSocketDidSecure:(AsyncSocket*)sock?

{?

??? NSLog(@"onSocket:%p did go a secureline:YES",sock);?

}?

(4)遇到錯(cuò)誤時(shí)關(guān)閉連接?

-(void)onSocket:(AsyncSocket*)sock willDisconnectWithError:(NSError *)err?

{?

??? NSLog(@"onSocket:%p will disconnectwith error:%@",sock,err);?

}?

(5)斷開連接?

-(void)onSocketDidDisconnect:(AsyncSocket*)sock?

{?

???NSLog(@"onSocketDidDisconnect:%p",sock);?

}?

6、關(guān)于NSData對(duì)象

socket無論收發(fā)數(shù)據(jù)都使用NSData對(duì)象,NSData帶一個(gè)id類型的data,指向數(shù)據(jù)的空間和長(zhǎng)度(length);

NSString和NSData對(duì)象的相互轉(zhuǎn)換:

NSString à NSData

NSData * xmlData=[@”testdata”dataUsingEncoding:NSUTF8StringEncoding];

NSDataàNSString

NSData *data;

NSString*str=[[NSString alloc]initWithData:dataencoding:NSUTF8StringEncoding];

?

7、發(fā)送數(shù)據(jù)

調(diào)用AsyncSocket的 writeData方法來發(fā)送數(shù)據(jù):??

-(void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeouttag:(long)tag;

Timeout一般設(shè)置-1,tag值要保證服務(wù)器和客戶端一致;

數(shù)據(jù)發(fā)送出去以后必然有專門的方法來處理發(fā)出的數(shù)據(jù),這個(gè)方法就是:

-(void)onSocket(AsyncSocket*)sock didWriteDataWithTag:(long)tag

socket發(fā)送數(shù)據(jù)是以棧的形式存放,所有數(shù)據(jù)放在一個(gè)棧中,存取時(shí)會(huì)出現(xiàn)粘包的現(xiàn)象,所以很多時(shí)候服務(wù)器在收發(fā)數(shù)據(jù)時(shí)是以先發(fā)送內(nèi)容字節(jié)長(zhǎng)度,再發(fā)送內(nèi)容的形式,得到數(shù)據(jù)時(shí)也是先得到一個(gè)長(zhǎng)度,再根據(jù)這個(gè)長(zhǎng)度在棧中讀取這個(gè)長(zhǎng)度的字節(jié)流,如果是這種情況,發(fā)送數(shù)據(jù)時(shí)只需在發(fā)送內(nèi)容前發(fā)送一個(gè)長(zhǎng)度,發(fā)送方法與發(fā)送內(nèi)容一樣。

?

8、接收socket數(shù)據(jù)

socket數(shù)據(jù)經(jīng)過處理后,如果成功得到數(shù)據(jù),就會(huì)調(diào)用方法接收數(shù)據(jù):

-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag

【注】收發(fā)數(shù)據(jù)中必須注意是添加 [sock readDataWithTimeout:-1 tag:0];否則接收不到數(shù)據(jù),并且這個(gè)函數(shù)在數(shù)據(jù)返回就必須調(diào)用一次。

?

9、socket的斷開連接與重連

首先我們需要了解的就是連接斷開的集中情況,在平時(shí)使用網(wǎng)絡(luò)的時(shí)候最容易出現(xiàn)的就是服務(wù)器斷開連接、用戶主動(dòng)斷開(即退出應(yīng)用程序)和不同IP同時(shí)登陸同一個(gè)賬號(hào)被迫掉線,在Demo中我們可以聲明一個(gè)枚舉類來標(biāo)注socket的斷開方式:enum{

??? SocketOfflineByServer,// 服務(wù)器掉線,默認(rèn)為0

??? SocketOfflineByUser,? // 用戶主動(dòng)cut

};

聲明一個(gè)斷開連接的方法:-(void)cutOffSocket;

在實(shí)現(xiàn)斷開連接方法的時(shí)候聲明是由用戶主動(dòng)斷開連接的,這樣在socket斷開的時(shí)候就知道是服務(wù)器出了問題還是用戶退出了連接。

類似QQ這類軟件會(huì)存在一個(gè)斷線重連的方法,如果是服務(wù)器端強(qiáng)制退出了連接,就需要立刻重連保證用戶正常在線,如果是用戶在客戶端正常退出,就不進(jìn)行操作。這就需要實(shí)現(xiàn)如下方法:

-(void)onSocketDidDisconnect:(AsyncSocket*)sock

{

??? NSLog(@"sorry the connect is failure%ld",sock.userData);

??? if (sock.userData == SocketOfflineByServer){

??????? // 服務(wù)器掉線,重連

??????? [self socketConnectHost];

??? }

??? else if (sock.userData ==SocketOfflineByUser) {

??????? // 如果由用戶斷開,不進(jìn)行重連

??????? return;

??? }

}

socket深層次的東西還有好多有待研究,我也沒有加入具體的Demo實(shí)現(xiàn),只是在瀏覽了別人的博客的基礎(chǔ)上對(duì)一些上層的東西做一下歸納收錄以備后用,底層的框架還需要在以后的工作中慢慢挖掘,如果大家有更加準(zhǔn)確有深度的socket知識(shí)還望能夠一起共享一下。

?

我的博客地址: http://blog.csdn.net/qadq211314

文檔參考:http://my.oschina.net/amoyai/blog/91694

http://my.oschina.net/u/937568/blog/127082

http://blog.csdn.net/zltianhen/article/details/6560322

http://blog.csdn.net/jeepxiaozi/article/details/9154925

http://my.oschina.net/joanfen/blog/287238

總結(jié)

以上是生活随笔為你收集整理的浅学socket及iOS中的AsyncSocket框架的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。