1.Socket是個(gè)什么玩意
socket起源于Unix,而Unix/Linux基本哲學(xué)之一就是“一切皆文件”笤闯,都可以用“打開open –> 讀寫write/read –> 關(guān)閉close”模式來操作堕阔。我的理解就是Socket就是該模式的一個(gè)實(shí)現(xiàn),socket即是一種特殊的文件颗味,一些socket函數(shù)就是對其進(jìn)行的操作(讀/寫IO超陆、打開、關(guān)閉)
2.長鏈接
在我們實(shí)際開發(fā)中浦马,除了即時(shí)通信时呀,如果沒有特殊要求,在請求數(shù)據(jù)的時(shí)候我們可以通過get捐韩、post來請求數(shù)據(jù)退唠,通常是這樣的,我:發(fā)送一個(gè)請求http://192.123.23.2:8888 然后后面拼上你需要的參數(shù)或者放在請求body里面荤胁,然后服務(wù)器接收到請求返回給我一些數(shù)據(jù),如果我不發(fā)送請求屎债,服務(wù)器是不會返送給我數(shù)據(jù)的仅政。當(dāng)然有一些需求是需要一直跟服務(wù)器有數(shù)據(jù)的交換垢油,這個(gè)時(shí)候我們就需要超鏈接了。
隨時(shí)可以接收到服務(wù)器給我的數(shù)據(jù)
3.介紹一些函數(shù)(c語言)
3.1 socket() 函數(shù)
int socket(int domain, int type, int protocol);
- 1.domain:即協(xié)議域圆丹,又稱為協(xié)議族(family)滩愁。常用的協(xié)議族有,AF_INET辫封、AF_INET6硝枉、AF_LOCAL(或稱AF_UNIX,Unix域socket)倦微、AF_ROUTE等等妻味。協(xié)議族決定了socket的地址類型,在通信中必須采用對應(yīng)的地址欣福,如AF_INET決定了要用ipv4地址(32位的)與端口號(16位的)的組合责球、AF_UNIX決定了要用一個(gè)絕對路徑名作為地址。
- 2.type:指定socket類型拓劝。常用的socket類型有雏逾,SOCK_STREAM、SOCK_DGRAM郑临、SOCK_RAW栖博、SOCK_PACKET、SOCK_SEQPACKET等等(socket的類型有哪些厢洞?)仇让。
- 3.protocol:故名思意,就是指定協(xié)議犀变。常用的協(xié)議有妹孙,IPPROTO_TCP、IPPTOTO_UDP获枝、IPPROTO_SCTP蠢正、IPPROTO_TIPC等,它們分別對應(yīng)TCP傳輸協(xié)議省店、UDP傳輸協(xié)議嚣崭、STCP傳輸協(xié)議、TIPC傳輸協(xié)議
3.2 gethostbyname()函數(shù)說明
struct hostent *gethostbyname(const char *name);
//這個(gè)函數(shù)的傳入值是域名或者主機(jī)名懦傍,例如"www.google.cn"等等雹舀。傳出值,是一個(gè)hostent的結(jié)構(gòu)粗俱。如果函數(shù)調(diào)用失敗说榆,將返回NULL。
/*
返回hostent結(jié)構(gòu)體類型指針
struct hostent
{
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
#define h_addr h_addr_list[0]
};
*/
3.3 connect() 函數(shù)
int connect(int, const struct sockaddr *, socklen_t)
connect函數(shù)的第一個(gè)參數(shù)即為客戶端的socket描述字,第二參數(shù)為服務(wù)器的socket地址签财,第三個(gè)參數(shù)為socket地址的長度串慰。客戶端通過調(diào)用connect函數(shù)來建立與TCP服務(wù)器的連接
不多嗶嗶唱蒸,進(jìn)入正題 (上代碼)
NSString *host = @"123.2.3.1";
NSNumber *port = @8888; //?< 端口
//創(chuàng)建socket 返回的int 就象文件句柄一樣 我們直接用這個(gè)descriptor來操作socket
int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
if (socketFileDescriptor == -1) {
NSLog(@"創(chuàng)建失敗");
return;
}
//創(chuàng)建一個(gè)結(jié)構(gòu)體 gethostbyname函數(shù)根據(jù)域名解析出服務(wù)器的ip地址邦鲫,它返回一個(gè)結(jié)構(gòu)體struct hostent:
/*
* Structures returned by network data base library. All addresses are
* supplied in host order, and returned in network order (suitable for
* use in system calls).
*/
struct hostent *remotehostEnt = gethostbyname([host UTF8String]);
if (remotehostEnt == NULL) {
close(socketFileDescriptor);
NSLog(@"無法解析服務(wù)器主機(jī)名");
return;
}
//結(jié)構(gòu)體指針 指向list of addresses from name server 服務(wù)器列表的第一位 即為h_addr_list[0],表示第一個(gè)地址神汹,這個(gè)符號其實(shí)是兼容老系統(tǒng)而存在的
struct in_addr *remoteIndAddr = (struct in_addr *)remotehostEnt -> h_addr;
//設(shè)置socket參數(shù)
struct sockaddr_in socketParamers;
socketParamers.sin_family = AF_INET; //?< internetwork: UDP, TCP
socketParamers.sin_addr = *remoteIndAddr; //?< 主機(jī)地址
socketParamers.sin_port = htons([port intValue]);
//連接socket
int result = connect(socketFileDescriptor, (struct sockaddr *) &socketParamers, sizeof(socketParamers));
if (result == -1) {
close(socketFileDescriptor);
NSLog(@"連接失敗");
return;
}
NSLog(@"連接成功");