TCP是面向鏈接的,安全可靠的傳輸層協議。TCP的程序基本框架設計圖:編程
image安全
注意:Socket通訊必定有要服務端和客戶端。 1.1 TCP Socket客戶端服務器
客戶端的工做流程:首先調用socket函數建立一個Socket,而後指定服務端的IP地址和端口號,就能夠調用sendto將字符串傳送給服務器端,並能夠調用recvfrom接收服務器端返回的字符串,最後關閉該socket。網絡
筆者這裏分紅了六步:框架
第一步:建立socket並配置socket 第二步:調用bind綁定監聽ip和端口號 第三步:調用connect鏈接服務器 第四步:調用getsockname獲取套接字信息 第五步:調用send發送消息到服務器端 第六步:調用close關閉socket 這裏沒有寫接收來自服務器端的消息,你們能夠自行添加。socket
1.1.1 客戶端的代碼實現:tcp
(void)tcpClient { // 第一步:建立soket // TCP是基於數據流的,所以參數二使用SOCK_STREAM int error = -1; int clientSocketId = socket(AF_INET, SOCK_STREAM, 0); BOOL success = (clientSocketId != -1); struct sockaddr_in addr;函數
// 第二步:綁定端口號 if (success) { NSLog(@"client socket create success"); // 初始化 memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr);測試
// 指定協議簇爲AF_INET,好比TCP/UDP等 addr.sin_family = AF_INET;設計
// 監放任何ip地址 addr.sin_addr.s_addr = INADDR_ANY; error = bind(clientSocketId, (const struct sockaddr *)&addr, sizeof(addr)); success = (error == 0); }
if (success) { // p2p struct sockaddr_in peerAddr; memset(&peerAddr, 0, sizeof(peerAddr)); peerAddr.sin_len = sizeof(peerAddr); peerAddr.sin_family = AF_INET; peerAddr.sin_port = htons(1024);
// 指定服務端的ip地址,測試時,修改爲對應本身服務器的ip peerAddr.sin_addr.s_addr = inet_addr("192.168.1.107");
socklen_t addrLen; addrLen = sizeof(peerAddr); NSLog(@"will be connecting");
// 第三步:鏈接服務器 error = connect(clientSocketId, (struct sockaddr *)&peerAddr, addrLen); success = (error == 0);
if (success) { // 第四步:獲取套接字信息 error = getsockname(clientSocketId, (struct sockaddr *)&addr, &addrLen); success = (error == 0);
if (success) { NSLog(@"client connect success, local address:%s,port:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); // 這裏只發送10次 int count = 10; do { // 第五步:發送消息到服務端 send(clientSocketId, "哈哈,server您好!", 1024, 0); count--; // 告訴server,客戶端退出了 if (count == 0) { send(clientSocketId, "exit", 1024, 0); } } while (count >= 1); // 第六步:關閉套接字 close(clientSocketId); }
} else { NSLog(@"connect failed");
// 第六步:關閉套接字 close(clientSocketId);
} } }
1.2 TCP Socket服務器端
服務器端的工做流程:首先調用socket函數建立一個套接字,而後調用bind函數將其與本機地址以及一個本地端口號綁定,接收到一個客戶端時,服務器顯示該客戶端的IP地址,並將字串返回給客戶端。
筆者這裏分紅了五步:
第一步:建立socket並配置socket 第二步:調用bind綁定服務器本機ip及端口號 第三步:調用listen監聽客戶端的鏈接,並指定同時最多可以讓accept的數量 第四步:調用accept等待客戶端的鏈接 第五步:調用recvfrom接收來自客戶端的消息 第六步:調用close關閉socket 1.2.1 服務器端代碼實現
(void)tcpServer { // 第一步:建立socket int error = -1;
// 建立socket套接字 int serverSocketId = socket(AF_INET, SOCK_STREAM, 0); // 判斷建立socket是否成功 BOOL success = (serverSocketId != -1);
// 第二步:綁定端口號 if (success) { NSLog(@"server socket create success"); // Socket address struct sockaddr_in addr;
// 初始化全置爲0 memset(&addr, 0, sizeof(addr));
// 指定socket地址長度 addr.sin_len = sizeof(addr);
// 指定網絡協議,好比這裏使用的是TCP/UDP則指定爲AF_INET addr.sin_family = AF_INET;
// 指定端口號 addr.sin_port = htons(1024);
// 指定監聽的ip,指定爲INADDR_ANY時,表示監聽全部的ip addr.sin_addr.s_addr = INADDR_ANY;
// 綁定套接字 error = bind(serverSocketId, (const struct sockaddr *)&addr, sizeof(addr)); success = (error == 0); }
// 第三步:監聽 if (success) { NSLog(@"bind server socket success"); error = listen(serverSocketId, 5); success = (error == 0); }
if (success) { NSLog(@"listen server socket success");
while (true) { // p2p struct sockaddr_in peerAddr; int peerSocketId; socklen_t addrLen = sizeof(peerAddr);
// 第四步:等待客戶端鏈接 // 服務器端等待從編號爲serverSocketId的Socket上接收客戶鏈接請求 peerSocketId = accept(serverSocketId, (struct sockaddr *)&peerAddr, &addrLen); success = (peerSocketId != -1); if (success) { NSLog(@"accept server socket success,remote address:%s,port:%d", inet_ntoa(peerAddr.sin_addr), ntohs(peerAddr.sin_port)); char buf[1024]; size_t len = sizeof(buf); // 第五步:接收來自客戶端的信息 // 當客戶端輸入exit時才退出 do { // 接收來自客戶端的信息 recv(peerSocketId, buf, len, 0); if (strlen(buf) != 0) { NSString *str = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding]; if (str.length >= 1) { NSLog(@"received message from client:%@",str); } } } while (strcmp(buf, "exit") != 0); NSLog(@"收到exit信號,本次socket通訊完畢"); // 第六步:關閉socket close(peerSocketId); }
} } }