1 #import "ViewController.h" 2 //0、導入頭文件 3 #include <netinet/in.h> 4 #include <sys/socket.h> 5 #include <arpa/inet.h> 6 7 static const char *serevr_ip = "127.0.0.1"; 8 static const short server_port = 6969; 9 10 @interface ViewController () 11 12 @property (assign, nonatomic) int clientSocket; 13 14 @property (weak, nonatomic) IBOutlet UITextField *msgTextField; 15 @property (strong, nonatomic) IBOutletCollection(UITextView) NSArray *chatTextView; 16 17 @end 18 19 @implementation ViewController 20 21 - (void)viewDidLoad { 22 [super viewDidLoad]; 23 // Do any additional setup after loading the view, typically from a nib. 24 [self initSocket]; 25 } 26 27 - (void)initSocket{ 28 //一、建立 Socket 29 30 /* 31 參數 32 第一個參數: adress_family,協議簇 AF_INET ---> IPV4(本地主機通信) IPV6 AF_UNIX(本地主機通信,linux使用) 33 第二個參數: 數據格式----> SOCK_STREAM(TCP)/SOCK_DGRAM(UDP);TCP基於數據流傳輸,UDP基於數據報文傳輸 34 第三個參數: protocol IPPROTO_TCP,若是傳入 0 ,會自動根據第二個參數,選中合適的協議;服務端自動給你確認須要什麼協議 35 返回值: 成功 -----> 正值 失敗 -------> -1 36 */ 37 38 _clientSocket = socket(AF_INET, SOCK_STREAM, 0); 39 40 //二、鏈接服務器 41 struct sockaddr_in sAddr = {0}; 42 43 sAddr.sin_len = sizeof(sAddr);//長度 44 45 inet_aton(serevr_ip, &sAddr.sin_addr); //字節序,分爲:主機字節序(整數在主機中存放的順序)和網絡字節序。 46 47 sAddr.sin_port = htons(server_port); 48 49 sAddr.sin_family = AF_INET; //協議簇 50 51 /* 52 第一個參數: 客戶端 Socket 53 54 第二個參數: 指向數據結構 sockeAddr 的指針,其中包括目的端口和 IP地址 55 56 第三個參數: 結構體數據長度 57 58 返回值:成功 ----> 0 其餘 ----> 錯誤代號 59 */ 60 int connectFlag = connect(_clientSocket, (struct sockaddr *)&sAddr, sizeof(sAddr)); 61 62 if (connectFlag == 0) { 63 //開啓線程後要開爲一個長度線程 64 NSThread *thread = [[NSThread alloc] initWithTarget:self 65 selector:@selector(receiveAction) object:nil]; 66 [thread start]; 67 68 }else{ 69 NSLog(@"鏈接錯誤"); 70 71 } 72 } 73 74 75 - (void)receiveAction{ 76 while (1) { 77 //內容緩存區 78 char rec_msg[1024] = {0}; 79 80 /** 81 監聽服務端發送的數據 82 83 @param _clientSocket 客戶端Socket 84 @param rec_msg 發送內容地址,內容緩存區 85 @param rec_msg 發送內容長度 86 @param rec_msg 發送方式標識,通常爲 0 87 @return 成功---> 返回字節數,失敗---->SOCKET-ERROR 88 */ 89 recv(_clientSocket, rec_msg, sizeof(rec_msg), 0); 90 printf("----->%s\n",rec_msg); 91 } 92 } 93 94 - (void)sendMessage:(NSString *)msg{ 95 const char *send_Message = [msg cStringUsingEncoding:NSUTF8StringEncoding]; 96 send(_clientSocket,send_Message,strlen(send_Message) ,0); 97 } 98 99 - (IBAction)sendAction:(UIButton *)sender { 100 if ([_msgTextField.text isEqualToString:@""]) { 101 NSLog(@"發送消息不能爲空"); 102 return; 103 } 104 [self sendMessage:_msgTextField.text]; 105 } 106 107 - (void)didReceiveMemoryWarning { 108 [super didReceiveMemoryWarning]; 109 // Dispose of any resources that can be recreated. 110 } 111 112 113 @end
TCP鏈接之後進行通信可能會發生丟包事件,這時客戶端和服務器端就要進行必定的約定,定義一些 「/n」 之類的一些標識符。linux
打開一個終端端口,輸入:面試
nc -l 6969 //監聽客戶端數據的發送算法
而後運行客戶端的程序代碼,不然控制檯會打印:"鏈接錯誤";緩存
在模擬器中輸入:33333服務器
終端也會出現:33333網絡
在終端輸入:-----》》》welcome 即時通信數據結構
在程序的控制檯會打印:socket
終端如圖:ide
Socket服務器端代碼atom
代碼圖一:
代碼圖二:
代碼圖三:
代碼圖四:
代碼圖五:
面試題:
Socket 監聽一個端口,最多有多少個鏈接?
與客戶端最多有1024個鏈接,但同時能鏈接的請求最多5個。
服務器同一時刻,一個端口只能創建一個鏈接服務端,可是它會生成一個等待隊列,每個請求它都會放在這個請求隊列裏,根據某一算法在某一時刻處理哪一個請求。