Socket 網路編程,socket網路編程
1.TCP/IP、UDP
TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制通訊協定/網間協議,是一個工業標準的協議集,它是為廣域網路(WANs)設計的。
UDP(User Data Protocol,使用者資料包通訊協定)是與TCP相對應的協議。它是屬於TCP/IP協議族中的一種。
下面這張圖,表明了這些協議的關係,TCP/IP協議族包括運輸層、網路層、鏈路層:
2.Socket
在圖1中,我們沒有看到Socket的影子,那麼它到底在哪裡呢?還是用圖來說話,一目瞭然。
Socket是應用程式層與TCP/IP協議族通訊的中間軟體抽象層,它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面,對使用者來說,一組簡單的介面就是全部,讓Socket去組織資料,以符合指定的協議。
3.使用socket
前人已經給我們做了好多的事了,網路間的通訊也就簡單了許多,但畢竟還是有挺多工作要做的。以前聽到Socket編程,覺得它是比較高深的編程知識,但是只要弄清Socket編程的工作原理,神秘的面紗也就揭開了。
一個生活中的情境。你要打電話給一個朋友,先撥號,朋友聽到電話鈴聲後提起電話,這時你和你的朋友就建立起了串連,就可以講話了。等交流結束,掛斷電話結束此次交談。生活中的情境就解釋了這工作原理,也許TCP/IP協議族就是誕生於生活中,這也不一定。
4.程式碼範例
#import "ViewController.h" #import <sys/socket.h> #import <netinet/in.h> #import <arpa/inet.h> @interface ViewController () // 用戶端 socket @property (nonatomic, assign) int clientSocket; @property (nonatomic, weak) IBOutlet UIWebView *myWebView; @end @implementation ViewController /** ======= 要求標頭 ======= 1> 請求行 GET / HTTP/1.1 GET 表示從伺服器"拿"資料 / 訪問伺服器的根目錄 HTTP/1.1 HTTP的協議以及版本 2> 要求標頭 Host: 要訪問的主機 User-Agent: 使用者代理程式,告訴伺服器用戶端的類型 Accept: 告訴伺服器用戶端支援的資料格式 Accept-Language: 告訴伺服器用戶端支援的語言 Accept-Encoding: 告訴伺服器用戶端支援的解壓縮類型 HTTP請求本身的格式,是字串格式的,最末一行,以 \n\n 結束,表示所有請求的內容發送完畢,伺服器可以處理! 提示:key 值是 HTTP 協議定義的,不能隨意更改! ==========響應 =========== 1> 狀態行 HTTP/1.1 200 OK HTTP/1.1 HTTP的協議以及版本 200 狀態代碼(404) 2XX 成功 4XX 用戶端錯誤 5XX 伺服器錯誤 2> 回應標頭,伺服器告訴用戶端的一些資訊 提示:響應的資訊,通常在開發“下載”功能時,才會使用,平時用不著 Date: 響應日期 Server: 伺服器的資訊 // 檔案長度 Content-Length: 24 3> 資料實體,從伺服器返回的位元據! println("hello world!"); */ - (void)viewDidLoad { [super viewDidLoad]; // http 連接埠是 80 if ([self connectToHost:@"61.135.169.125" port:80]) { NSLog(@"串連成功"); } // 發送訊息給 網頁伺服器 // 建立請求字串 NSString *request = @"GET / HTTP/1.1\n" "Host: www.baidu.com\n" "User-Agent: iPhone AppleWebKit\n\n"; // 對結果的處理 NSString *result = [self sendAndRecv:request]; // 找 \r\n 的出現的位置 NSRange range = [result rangeOfString:@"\r\n\r\n"]; // 判斷是否找到 if (range.location == NSNotFound) { NSLog(@"html 錯誤"); return; } NSString *html = [result substringFromIndex:range.location]; [self.myWebView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://www.baidu.com"]]; } - (BOOL)connectToHost:(NSString *)host port:(int)port { // 1. socket /** 參數 domain: 協議域,AF_INET type: Socket 類型,SOCK_STREAM(流 TCP)/SOCK_DGRAM(報文,提示: 在有些公司的程式員給伺服器發送資料,會說:發送報文) protocol: IPPROTO_TCP,提示:如果輸入0,會根據第二個參數,自動選擇協議 傳回值 socket 如果>0,就是正確的 */ self.clientSocket = socket(AF_INET, SOCK_STREAM, 0); // 2. 串連到另外一台電腦 /** 參數 1> 用戶端socket 2> 指向資料結構sockaddr的指標,其中包括目的連接埠和IP地址 C 語言中沒有對象,實現都是通過結構體來實現的 3> 結構體資料長度 傳回值 0 成功/其他 錯誤代號,很多C語言的程式都會如此設計,原因:成功只有一個,失敗會有很多種! C 語言中,通常是非零即真 */ struct sockaddr_in serverAddress; // 1> 地址 inet_addr 可以將 ip 地址轉換成整數 // 提示:在網路上的使用的很多資料,需要做位元組翻轉 serverAddress.sin_addr.s_addr = inet_addr(host.UTF8String); // 2> 連接埠 htons 可以將連接埠轉換成整數 // 連接埠號碼同樣要做位元組翻轉 serverAddress.sin_port = htons(port); // 3> 協議 serverAddress.sin_family = AF_INET; // 在 C 語言中,通常傳遞結構體的指標同時,會傳遞結構體的尺寸 int result = connect(self.clientSocket, (const struct sockaddr *)&serverAddress, sizeof(serverAddress)); return (result == 0); } /** * 發送&接收訊息 */ - (NSString *)sendAndRecv:(NSString *)msg { // 3. 發送資料給伺服器 /** 參數 1> 用戶端socket 2> 發送內容地址 3> 發送內容長度 4> 發送方式標誌,一般為0 傳回值 如果成功,則返回傳送的位元組數,失敗則返回SOCKET_ERROR 提示:在很多C語言架構中,會將基礎資料型別 (Elementary Data Type)進行封裝,使用的時候,便於後續架構的調整 */ // 在 UTF8 編碼中,一個中文對應 3 個位元組 ssize_t sendLen = send(self.clientSocket, msg.UTF8String, strlen(msg.UTF8String), 0); // 4. 從伺服器接收資料 uint8_t buffer[1024]; // 1> 定義一個可變的位元據,方便拼勁 NSMutableData *dataM = [NSMutableData data]; // 伺服器返回的斷行符號計數 int count = 0; while (count == 0) { // 2> 接收資料 ssize_t recvLen = recv(self.clientSocket, buffer, sizeof(buffer), 0); [dataM appendBytes:buffer length:recvLen]; // 通過跟蹤,\r\n\r\n 需要繼續等待,\r\n 表示傳輸結束 // 取末尾一個位元組 uint8_t lastByte = buffer[recvLen - 1]; // 取倒數第三個位元組 uint8_t preLastByte = buffer[recvLen - 3]; if (lastByte == '\n' && preLastByte != '\n') { count++; } } return [[NSString alloc] initWithData:dataM encoding:NSUTF8StringEncoding]; } /** * 中斷連線 */ - (void)disconnect { // 5. 關閉串連 close(self.clientSocket); }@end
5. 延伸閱讀
1.Linux socket 編程:
http://www.ibm.com/developerworks/cn/education/linux/l-sock/l-sock.html
2. 網路編程學習筆記一:Socket編程:
http://blog.csdn.net/gneveek/article/details/8699198