在網(wǎng)絡(luò)中,兩個程序之間是通過一個雙向的通信連接來實現(xiàn)數(shù)據(jù)交換的册养。這個連接的一端為Socket
,又稱套接字
揣云,包含了終端的IP地址
捕儒、端口
冰啃、傳輸協(xié)議
等信息邓夕。
Socket是對TCP/IP的封裝
,但它并不是一個協(xié)議
阎毅,只是給程序員提供一個發(fā)送消息的接口
焚刚,程序員使用這個接口提供的方法來發(fā)送和接收消息
。
網(wǎng)絡(luò)通信其實就是Socket之間的通信扇调,數(shù)據(jù)在兩個Socket之間通過IO傳輸矿咕。
要想實現(xiàn)Socket的通信,大致經(jīng)歷3個步驟,分別是創(chuàng)建一個Socket并建立連接
碳柱、發(fā)送和接收信息
捡絮、斷開連接、
一莲镣、創(chuàng)建Socket福稳,建立連接
創(chuàng)建一個Socket對象,通過socket()函數(shù)
來實現(xiàn)
函數(shù)格式:
int socket(int domain,int type,int protocol);
domain: 協(xié)議域或者協(xié)議族,它決定了Socket的地址類型瑞侮,
通信中必須采用對應(yīng)的地址
type:指定Socket類型的圆,常用類型有
SOCK_STREAM、SOCK_DGRAM半火、SOCK_RAW越妈、SOCK_PACKET等
protocol:指定協(xié)議,常用協(xié)議有
IPPROTO_TCP钮糖、IPPROTO_UDP梅掠、IPPROTO_SCTP、IPPROTO_TIPC店归,
分別對應(yīng)TCP瓤檐、UDP、STCP娱节、TIPC傳輸協(xié)議挠蛉。
二、發(fā)送和接收信息
當(dāng)連接建立之后肄满,就可以發(fā)送和接收信息了谴古。發(fā)送信息通過send()函數(shù)來實現(xiàn)
ssize_t send(int,const void *,size_t,int)__DARWIN_ALIAS_C(send);
參數(shù)一:客戶端的Socket
參數(shù)二:發(fā)送內(nèi)容的地址
參數(shù)三:發(fā)送內(nèi)容的長度
參數(shù)四:發(fā)送內(nèi)容的標(biāo)志,一般為0稠歉,
如發(fā)送成功掰担,返回信息內(nèi)容的字節(jié)數(shù)
客戶端將信息發(fā)送給服務(wù)器后,服務(wù)器會接收這個信息怒炸,通過recv()函數(shù)實現(xiàn)
ssize_t send(int,void
*,size_t,int)__DARWIN_ALIAS_C(recv);
參數(shù)一:客戶端的Socket
參數(shù)二:接收內(nèi)容的緩沖地址
參數(shù)三:接收內(nèi)容的長度
參數(shù)四:接收的標(biāo)志带饱,如果為0表示阻塞式,
即會一直等待服務(wù)器返回數(shù)據(jù)
三阅羹、斷開連接
給服務(wù)器發(fā)送完信息勺疼,服務(wù)器回復(fù)信息后,需要斷開連接捏鱼,通過close()函數(shù)實現(xiàn)
int close(int);
四执庐、實戰(zhàn)-Socket聊天
Socket提供了發(fā)送和接收信息的接口,通過該接口實現(xiàn)了客戶端與服務(wù)器端的通信
創(chuàng)建工程导梆,設(shè)計界面
新建Single View Application應(yīng)用轨淌。 進入storyboard迂烁,拖拽1個label、2個button递鹉、3個Text Filed盟步。
建立效果大致如下:
控件對象的關(guān)聯(lián)
/** 主機名 */
@property (weak, nonatomic) IBOutlet UITextField *hostText;
/** 端口號 */
@property (weak, nonatomic) IBOutlet UITextField *portText;
/** 發(fā)送的消息 */
@property (weak, nonatomic) IBOutlet UITextField *msgText;
/** 回復(fù)的消息 */
@property (weak, nonatomic) IBOutlet UILabel *recvLabel;
/** Socket */
@property(nonatomic, assign) int clientSocket;
實現(xiàn)Socket聊天
- 導(dǎo)入 :
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
- 自定義方法,通過傳入一個IP地址和端口號連接到服務(wù)器 :
/** 連接到服務(wù)器 */
- (BOOL)connectHost:(NSString *)host port:(int)port{
//創(chuàng)建Socket對象
self.clientSocket = socket(AF_INET, SOCK_STREAM, 0);
//建立連接
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;//協(xié)議族
//IP躏结、查找機器
serverAddress.sin_addr.s_addr = inet_addr(host.UTF8String);
serverAddress.sin_port = htons(port);//端口址芯、查找程序
return (connect(self.clientSocket, (const struct sockaddr *)&serverAddress, sizeof(serverAddress))==0);
}
- 自定義方法,用于客戶端向服務(wù)器端發(fā)送一條信息
服務(wù)器端向客戶端回復(fù)一條信息:
/** 發(fā)送和接收 */
- (NSString *)sendAndRecv:(NSString *)message{
//發(fā)送信息
size_t sendMsg = send(self.clientSocket, message.UTF8String, strlen(message.UTF8String), 0);
//接收信息
uint8_t buffer[1024];//定義一個數(shù)組
ssize_t recvMsg = recv(self.clientSocket, buffer, sizeof(buffer), 0);
//獲取服務(wù)器返回的二進制數(shù)據(jù)
NSData *data = [NSData dataWithBytes:buffer length:recvMsg];
//轉(zhuǎn)化為字符串
NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return str;
}
- 自定義一個斷開連接的方法窜觉,用于中斷之前的連接
/** 斷開連接 */
- (void)disconnection{
close(self.clientSocket);
}
- 單擊'連接按鈕'谷炸,提示信息;單擊'發(fā)送按鈕'禀挫,接收到的信息顯示在label上
/** 單擊'連接按鈕'后事件 */
- (IBAction)clickConnectBtn {
BOOL result = [self connectHost:self.hostText.text port:self.portText.text.intValue];
self.recvLabel.text = result?@"成功":@"失敗";
}
/** 單擊'發(fā)送按鈕'后事件 */
- (IBAction)clickSendBtn {
self.recvLabel.text = [self sendAndRecv:self.msgText.text];
}
運行程序
Run程序成功后旬陡,填入對應(yīng)的主機名和端口號
[這里以12345為例]
,打開終端,輸入nc -lk 12345
语婴,單擊模擬器上的連接按鈕
描孟,底部標(biāo)簽提示成功后,在文本中輸入發(fā)送信息[例Hello]
砰左,點擊發(fā)送按鈕
匿醒,此時終端監(jiān)測到了發(fā)送來信息"Hello"。在終端中輸入"Hi"缠导,return之后廉羔,模擬器label提示"Hi"。這樣就成功的實現(xiàn)了
Socket聊天
僻造。效果圖