1.Socket簡介
Socket
百度百科:
網(wǎng)絡(luò)上的兩個程序通過一個雙向的通信連接實現(xiàn)數(shù)據(jù)的交換,這個連接的一端稱為一個socket霞溪。
Socket的英文原義是“孔”或“插座”中捆。作為BSD UNIX的進(jìn)程通信機(jī)制,取后一種意思殴蓬。通常也稱作"套接字"蟋滴,用于描述IP地址和端口,是一個通信鏈的句柄肖粮,可以用來實現(xiàn)不同虛擬機(jī)或不同計算機(jī)之間的通信尔苦。在Internet上的主機(jī)一般運行了多個服務(wù)軟件,同時提供幾種服務(wù)凌净。每種服務(wù)都打開一個Socket屋讶,并綁定到一個端口上,不同的端口對應(yīng)于不同的服務(wù)皿渗。Socket正如其英文原意那樣轻腺,像一個多孔插座贬养。一臺主機(jī)猶如布滿各種插座的房間琴庵,每個插座有一個編號,有的插座提供220伏交流電迷殿, 有的提供110伏交流電庆寺,有的則提供有線電視節(jié)目。 客戶軟件將插頭插到不同編號的插座懦尝,就可以得到不同的服務(wù)。
圖說Socket
Socket是應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層, 它是一組接口琅轧。
2.TCP和UDP的區(qū)別
TCP
面向連接鹰晨、傳輸可靠(保證數(shù)據(jù)正確性,保證數(shù)據(jù)順序)止毕、用于傳輸大量數(shù)據(jù)(流模式)、速度慢扁凛,建立連接需要開銷較多(時間谨朝,系統(tǒng)資源)。
UDP
面向非連接字币、傳輸不可靠、用于傳輸少量數(shù)據(jù)(數(shù)據(jù)包模式)士复、速度快。
區(qū)別
關(guān)于TCP是一種流模式的協(xié)議便贵,UDP是一種數(shù)據(jù)報模式的協(xié)議冗荸,這里要說明一下,TCP是面向連接的盔粹,也就是說魂毁,在連接持續(xù)的過程中,socket中收到的數(shù)據(jù)都是由同一臺主機(jī)發(fā)出的(劫持什么的不考慮),因此税稼,知道保證數(shù)據(jù)是有序的到達(dá)就行了,至于每次讀取多少數(shù)據(jù)自己看著辦只祠。
而UDP是無連接的協(xié)議扰肌,也就是說,只要知道接收端的IP和端口盗舰,且網(wǎng)絡(luò)是可達(dá)的桂躏,任何主機(jī)都可以向接收端發(fā)送數(shù)據(jù)。這時候蛮位,如果一次能讀取超過一個報文的數(shù)據(jù)鳞绕,則會亂套。比如们何,主機(jī)A向發(fā)送了報文P1垂蜗,主機(jī)B發(fā)送了報文P2解幽,如果能夠讀取超過一個報文的數(shù)據(jù)烘苹,那么就會將P1和P2的數(shù)據(jù)合并在了一起,這樣的數(shù)據(jù)是沒有意義的霜定。
3.UDP的Socket具體實現(xiàn)
iOS提供了Socket網(wǎng)絡(luò)編程的接口CFSocket廊鸥,不過這里使用BSD Socket。
基本UDP客戶—服務(wù)器程序設(shè)計基本框架流程圖
常用的Socket類型有兩種:流式Socket(SOCK_STREAM)和數(shù)據(jù)報式Socket(SOCK_DGRAM)。流式是一種面向連接的Socket吆视,針對于面向連接的TCP服務(wù)應(yīng)用;數(shù)據(jù)報式Socket是一種無連接的Socket您觉,對應(yīng)于無連接的UDP服務(wù)應(yīng)用瘸洛。
Socket調(diào)用的主要庫函數(shù)
創(chuàng)建套接字
Socket(af, type, protocol)
建立地址和套簽字的練習(xí)
bind(sockid, local addr, addrlen)
服務(wù)器端監(jiān)聽客戶端的請求
listen(Sockid, quenlen)
建立服務(wù)器/客戶端的連接(面向連接TCP)
客戶端請求連接
Connect(Sockid, destaddr, addrlen)
服務(wù)器端等待從編號為Sockid的Socket上接收客戶連接請求
newsockid = accept(Sockid棺滞,Clientaddr, paddrlen)
發(fā)送/接收數(shù)據(jù)
面向?qū)ο?/p>
send(sockid, buff, bufflen)
recv()
面向無連接
sendto(sockid, buff, ..., addrlen)
recvform()
釋放嵌套字
close(socked)
UDP下Socket具體實現(xiàn)
服務(wù)器的工作流程:首先調(diào)用socket函數(shù)創(chuàng)建一個Socket恶导,然后調(diào)用bind函數(shù)將其與本機(jī)地址以及一個本地端口號綁定郁妈,接收到一個客戶端時,服務(wù)器顯示該客戶端的IP地址噩咪,并將字串返回給客戶端胃碾。
服務(wù)器參考代碼:
#import <Foundation/Foundation.h>
#import <sys/socket.h>
#import <sys/types.h>
#import <netinet/in.h>
#import <arpa/inet.h>
int main(int argc, const char * argv[]) {
int ser_sockfd = 0;
int len = 0;
//int addrlen;
socklen_t addrlen = 0;
char seraddr[100] = {0};
struct sockaddr_in ser_addr = {0};
/*建立socket*/
ser_sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(ser_sockfd < 0)
{
printf("I cannot socket success\n");
return 1;
}
/*填寫sockaddr_in 結(jié)構(gòu)*/
addrlen = sizeof(struct sockaddr_in);
bzero(&ser_addr, addrlen);
ser_addr.sin_family = AF_INET;
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ser_addr.sin_port = htons(1024);
/*綁定客戶端*/
if(bind(ser_sockfd, (struct sockaddr *)&ser_addr, addrlen) < 0)
{
printf("connect");
return 1;
}
while(1)
{
bzero(seraddr, sizeof(seraddr));
len = recvfrom(ser_sockfd, seraddr, sizeof(seraddr), 0, (struct sockaddr*)&ser_addr, &addrlen);
/*顯示client端的網(wǎng)絡(luò)地址*/
printf("receive from %s\n", inet_ntoa(ser_addr.sin_addr));
/*顯示客戶端發(fā)來的字串*/
printf("recevce:%s", seraddr);
/*將字串返回給client端*/
sendto(ser_sockfd, seraddr, len, 0, (struct sockaddr*)&ser_addr, addrlen);
}
return 0;
}
客戶端參考代碼
#import <Foundation/Foundation.h>
#import <sys/socket.h>
#import <sys/types.h>
#import <netinet/in.h>
#import <arpa/inet.h>
int GetServerAddr(char *addrname)
{
printf("please input server addr:");
scanf("%s", addrname);
return 1;
}
int main(int argc, const char * argv[]) {
int cli_sockfd = 0;
int len = 0;
socklen_t addrlen = 0;
char seraddr[14] = {0};
struct sockaddr_in cli_addr = {0};
char buffer[256] = {0};
GetServerAddr(seraddr);
/* 建立socket*/
cli_sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(cli_sockfd < 0)
{
printf("I cannot socket success\n");
return 1;
}
/* 填寫sockaddr_in*/
addrlen = sizeof(struct sockaddr_in);
bzero(&cli_addr, addrlen);
cli_addr.sin_family = AF_INET;
cli_addr.sin_addr.s_addr = inet_addr(seraddr);
//cli_addr.sin_addr.s_addr=htonl(INADDR_ANY);
cli_addr.sin_port = htons(1024);
bzero(buffer,sizeof(buffer));
/* 從標(biāo)準(zhǔn)輸入設(shè)備取得字符串*/
len = read(STDIN_FILENO, buffer, sizeof(buffer));
/* 將字符串傳送給server端*/
sendto(cli_sockfd, buffer, len, 0, (struct sockaddr*)&cli_addr, addrlen);
/* 接收server端返回的字符串*/
len = recvfrom(cli_sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&cli_addr, &addrlen);
//printf("receive from %s\n",inet_ntoa(cli_addr.sin_addr));
printf("receive: %s", buffer);
close(cli_sockfd);
return 0;
}