版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2019.07.09 星期二 |
前言
實時通信在很多App上都有應(yīng)用,包括我在上一家公司做的App也使用了實時通信技術(shù)叉瘩,用于私聊和群聊涵但,所以這里特意開一個專題一起學(xué)習(xí)一下實時通信技術(shù)涧尿。
開始
首先看一下寫作環(huán)境
Swift 5, iOS 12, Xcode 10
從一開始履腋,人類就夢想有更好的方式與他的弟兄們進行廣泛的溝通珊燎。 從信鴿到無線電波惭嚣,我們一直在努力更清晰有效地進行溝通。
在這個現(xiàn)代時代悔政,一種技術(shù)已成為我們尋求相互理解的重要工具:簡潔的網(wǎng)絡(luò)socket
晚吞。
現(xiàn)在位于我們現(xiàn)代網(wǎng)絡(luò)基礎(chǔ)設(shè)施第4層layer 4的某個地方,sockets
是任何在線通信的核心谋国,從短信到在線游戲槽地。
1. Why Sockets?
您可能想知道,“為什么我首先需要比URLSession
更靠近底層的東西芦瘾?”(如果您不想知道捌蚊,那么請繼續(xù)并假裝你想知道。)
這是一個好問題旅急!與URLSession
通信的事情是它基于HTTP網(wǎng)絡(luò)協(xié)議逢勾。使用HTTP牡整,通信以請求 - 響應(yīng)(request-response)
方式發(fā)生藐吮。這意味著大多數(shù)應(yīng)用程序中的大多數(shù)網(wǎng)絡(luò)代碼遵循相同的模式:
- 1) 從服務(wù)器請求一些JSON。
- 2) 在回調(diào)或代理方法中接收和使用所述JSON逃贝。
但是谣辞,當(dāng)你希望服務(wù)器能夠告訴你的應(yīng)用程序時呢?這對HTTP來說并不是很有效沐扳。
當(dāng)然泥从,您可以通過不斷ping
服務(wù)器并查看它是否有更新(也就是輪詢)來使其工作,或者您可以使用長輪詢long-polling等技術(shù)沪摄。但是這些技術(shù)可能會有點不自然躯嫉,每個都有自己的陷阱。
在一天結(jié)束時杨拐,如果它不適合這項工作祈餐,為什么要限制自己使用這種請求 - 響應(yīng)模式呢?
在這個iOS流教程中哄陶,您將學(xué)習(xí)如何使用底層抽象級別并直接使用sockets
來創(chuàng)建實時聊天室應(yīng)用程序帆阳。
您的聊天室應(yīng)用程序?qū)⑹褂迷诹奶鞎捚陂g保持打開狀態(tài)的輸入和輸出流,而不是使用每個客戶端都必須檢查服務(wù)器是否有新消息這種方式屋吨。
首先蜒谤,打開聊天應(yīng)用程序和用Go
編寫的簡單服務(wù)器。
您不必?fù)?dān)心自己編寫任何Go代碼至扰,但是您需要啟動并運行此服務(wù)器才能為其編寫客戶端鳍徽。
2. Getting Your Server to Run
初始材料中的服務(wù)器使用Go
并為您預(yù)編譯。 如果您不是那種信任您在網(wǎng)絡(luò)上找到的預(yù)編譯可執(zhí)行文件的人敢课,您可以使用材料中的源代碼自行編譯旬盯。
要運行預(yù)編譯的服務(wù)器,請打開終端,導(dǎo)航到初始材料目錄并輸入以下命令:
sudo ./server
出現(xiàn)提示時胖翰,請輸入您的密碼接剩。 輸入密碼后,您應(yīng)該看到:Listening on 127.0.0.1:80
萨咳。
注意:您必須使用特權(quán)運行服務(wù)器 - 因此是
sudo
命令 - 因為它偵聽端口80
懊缺。所有小于1024
的端口號都是特權(quán)端口,需要root訪問權(quán)限才能綁定它們培他。
您的聊天服務(wù)器已準(zhǔn)備就緒鹃两! 您現(xiàn)在可以跳到下一部分。
如果您想自己編譯服務(wù)器舀凛,則需要使用Homebrew
安裝Go
俊扳。
如果您還沒有Homebrew
,那么您必須先安裝它然后才能開始猛遍。 打開終端并粘貼以下行:
/usr/bin/ruby -e \
"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
然后使用下面這個命令安裝Go
:
brew install go
完成后馋记,導(dǎo)航到入門材料的目錄并使用build
構(gòu)建服務(wù)器。
go build server.go
最后懊烤,您可以使用本節(jié)開頭列出的命令啟動服務(wù)器梯醒。
3. Looking at the Existing App
接下來,打開DogeChat
項目并構(gòu)建并運行它以查看已經(jīng)為您構(gòu)建的內(nèi)容腌紧。
如上所示茸习,DogeChat
當(dāng)前設(shè)置為允許用戶輸入用戶名然后進入聊天室。
不幸的是壁肋,上一個工作的人不知道如何編寫聊天應(yīng)用程序号胚,所以你得到的只是用戶界面和基本的管道,你必須實現(xiàn)網(wǎng)絡(luò)層浸遗。
Creating a Chat Room
要開始實際編碼猫胁,請導(dǎo)航到ChatRoomViewController.swift
。在這里乙帮,您可以看到您有一個準(zhǔn)備好的視圖控制器杜漠,并且能夠從輸入欄接收字符串作為消息。它還可以通過table view
顯示消息察净,其中包含使用Message
對象配置的自定義單元格驾茴。
由于您已經(jīng)有了ChatRoomViewController
,因此創(chuàng)建一個ChatRoom
類來處理繁重的工作是有意義的氢卡。
在開始編寫新類之前锈至,請快速列出其職責(zé)。您希望此類負(fù)責(zé)以下任務(wù):
- 1) 打開與聊天室服務(wù)器的連接译秦。
- 2) 允許用戶通過提供用戶名加入聊天室峡捡。
- 3) 允許用戶發(fā)送和接收消息击碗。
- 4) 完成后關(guān)閉連接。
既然您知道自己想要什么们拙,請按Command-N
創(chuàng)建一個新文件稍途。選擇Swift文件并將其命名為ChatRoom
。
1. Creating Input and Output Streams
接下來砚婆,將ChatRoom.swift
中的代碼替換為:
import UIKit
class ChatRoom: NSObject {
//1
var inputStream: InputStream!
var outputStream: OutputStream!
//2
var username = ""
//3
let maxReadLength = 4096
}
在這里械拍,您已經(jīng)定義了ChatRoom
類并聲明了您需要進行通信的屬性。
- 1) 首先装盯,聲明輸入和輸出流坷虑。 通過一起使用這對類,您可以在應(yīng)用程序和聊天服務(wù)器之間創(chuàng)建基于
socket
的連接埂奈。 當(dāng)然迄损,您將通過輸出流發(fā)送消息并通過輸入流接收消息。 - 2) 接下來账磺,您定義
username
芹敌,您將在其中存儲當(dāng)前用戶的名稱。 - 3) 最后绑谣,您聲明
maxReadLength
党窜。 此常量會限制您可以在任何單個消息中發(fā)送的數(shù)據(jù)量拗引。
接下來借宵,轉(zhuǎn)到ChatRoomViewController.swift
并將chat room
屬性添加到頂部的屬性列表中。
let chatRoom = ChatRoom()
現(xiàn)在您已經(jīng)設(shè)置了類的基本結(jié)構(gòu)矾削,現(xiàn)在是時候敲掉清單中的第一件事了:打開應(yīng)用程序和服務(wù)器之間的連接壤玫。
Opening a Connection
返回ChatRoom.swift
,在屬性定義下面添加以下方法:
func setupNetworkCommunication() {
// 1
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
// 2
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
"localhost" as CFString,
80,
&readStream,
&writeStream)
}
這是發(fā)生了什么:
- 1) 首先哼凯,設(shè)置兩個未初始化的套接字流欲间,而不進行自動內(nèi)存管理。
- 2) 然后將讀取和寫入套接字流綁定在一起断部,并將它們連接到主機的套接字猎贴,在這種情況下,它位于端口80上蝴光。
該函數(shù)有四個參數(shù)她渴。第一個是初始化流時要使用的分配器allocator
類型。你應(yīng)該盡可能使用kCFAllocatorDefault
蔑祟,但如果你遇到需要的東西有點不同的情況趁耗,還有其他選擇。
接下來疆虚,指定hostname
苛败。在這種情況下满葛,您將連接到本地計算機;如果您有遠程服務(wù)器的特定IP地址罢屈,您也可以在此處使用它嘀韧。
然后,指定您通過port 80
連接缠捌,這是服務(wù)器偵聽的端口乳蛾。
最后,將指針傳遞給讀取和寫入流鄙币,以便函數(shù)可以使用它在內(nèi)部創(chuàng)建的連接讀取和寫入流來初始化它們肃叶。
現(xiàn)在您已經(jīng)初始化了流,您可以通過在setupNetworkCommunication()
的末尾添加以下行來存儲對它們的保留引用:
inputStream = readStream!.takeRetainedValue()
outputStream = writeStream!.takeRetainedValue()
在非管理對象上調(diào)用takeRetainedValue()
允許您同時獲取保留的引用并去掉不平衡的retain
十嘿,以便以后不會泄漏內(nèi)存因惭。 現(xiàn)在,您可以在需要時使用輸入和輸出流绩衷。
接下來蹦魔,您需要將這些流添加到run loop
中,以便您的應(yīng)用程序能夠正確地響應(yīng)網(wǎng)絡(luò)事件咳燕。 通過將這兩行添加到setupNetworkCommunication()
的末尾來實現(xiàn):
inputStream.schedule(in: .current, forMode: .common)
outputStream.schedule(in: .current, forMode: .common)
最后勿决,你準(zhǔn)備打開防洪閘了! 要開始派對招盲,請?zhí)砑拥?code>setupNetworkCommunication()的底部:
inputStream.open()
outputStream.open()
這就是它的全部內(nèi)容低缩。 要完成望门,請轉(zhuǎn)到ChatRoomViewController.swift
并將以下行添加到viewWillAppear(_ :)
:
chatRoom.setupNetworkCommunication()
您現(xiàn)在在客戶端應(yīng)用程序和在localhost
上運行的服務(wù)器之間建立了打開的連接辣恋。
如果需要,您可以構(gòu)建和運行您的應(yīng)用程序艾船,但是您會看到之前看到的相同內(nèi)容顶籽,因為您尚未嘗試對連接執(zhí)行任何操作玩般。
Joining the Chat
現(xiàn)在您已經(jīng)建立了與服務(wù)器的連接,現(xiàn)在是時候開始進行通信了礼饱! 你要說的第一件事就是你認(rèn)為自己到底是誰坏为。 之后,您將要開始向人們發(fā)送消息镊绪。
這提出了一個重點:由于您有兩種消息匀伏,因此您需要找到一種方法來區(qū)分它們。
1. The Communication Protocol
使用底層TCP級別的一個優(yōu)點是您可以定義自己的“協(xié)議”來決定消息是否有效镰吆。
使用HTTP
帘撰,您需要考慮所有那些討厭的動詞,如GET万皿,PUT和PATCH
摧找。 您需要構(gòu)建URL
并使用適當(dāng)?shù)?code>header和各種東西核行。
這里你只有兩種消息。 你可以發(fā)送:
iam:Luke
進入房間并告知世界你的消息蹬耘,你可以說:
msg:Hey, how goes it, man?
向房間里的其他人發(fā)送消息芝雪。
這很簡單但也很不安全,所以不要在工作中使用它综苔。
現(xiàn)在您已了解服務(wù)器的期望惩系,您可以在ChatRoom
上編寫一個方法以允許用戶進入聊天室。 它需要的唯一參數(shù)是所需的用戶名如筛。
要實現(xiàn)它堡牡,請在您剛剛在ChatRoom.swift
中編寫的setup
方法下面添加以下方法:
func joinChat(username: String) {
//1
let data = "iam:\(username)".data(using: .utf8)!
//2
self.username = username
//3
_ = data.withUnsafeBytes {
guard let pointer = $0.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
print("Error joining chat")
return
}
//4
outputStream.write(pointer, maxLength: data.count)
}
}
- 1) 首先,使用簡單的聊天室協(xié)議構(gòu)建您的消息杨刨。
- 2) 然后晤柄,您保存名稱,以便以后可以使用它來發(fā)送聊天消息妖胀。
- 3)
withUnsafeBytes(_ :)
提供了一種方便的方法來處理閉包安全范圍內(nèi)的某些數(shù)據(jù)的不安全指針版本芥颈。 - 4) 最后,將消息寫入輸出流赚抡。 這可能看起來比你想象的要復(fù)雜一點爬坑,但是
write(_:maxLength :)
引用了一個不安全的指向字節(jié)的指針作為你在上一步中創(chuàng)建的第一個參數(shù)。
現(xiàn)在您的方法已準(zhǔn)備就緒涂臣,打開ChatRoomViewController.swift
并添加一個調(diào)用以在viewWillAppear(_ :)
底部加入聊天盾计。
chatRoom.joinChat(username: username)
現(xiàn)在,構(gòu)建并運行您的應(yīng)用程序肉康。 輸入您的姓名闯估,然后點按return
以查看...
還是一樣沒變化?
現(xiàn)在灼舍,堅持下去吼和,有一個很好的解釋。 轉(zhuǎn)到您的終端骑素。 在Listening on 127.0.0.1:80
下炫乓,如果你的名字不是Brody
,你應(yīng)該看到Brody has joined
献丑,或類似的東西末捣。
這是個好消息,但你寧愿在手機屏幕上看到一些成功的跡象创橄。
Reacting to Incoming Messages
服務(wù)器發(fā)送傳入的消息箩做,例如您剛剛發(fā)送給房間中每個人的加入消息,包括您妥畏。 幸運的是邦邦,你的應(yīng)用程序已經(jīng)設(shè)置為在ChatRoomViewController
的消息表中顯示任何類型的傳入消息作為單元格安吁。
您需要做的就是使用inputStream
來捕獲這些消息,將它們轉(zhuǎn)換為Message
對象燃辖,然后將它們傳遞給該表來完成它的工作鬼店。
為了對收到的消息做出反應(yīng),您需要做的第一件事就是讓您的chat room
成為輸入流的代理黔龟。
為此妇智,請轉(zhuǎn)到ChatRoom.swift
的底部并添加以下擴展名。
extension ChatRoom: StreamDelegate {
}
既然您已經(jīng)說過遵循StreamDelegate
氏身,那么您可以聲稱自己是inputStream
的代理巍棱。
在調(diào)度調(diào)用schedule(in:forMode:)
之前直接將以下行添加到setupNetworkCommunication()
:
inputStream.delegate = self
接下來,將此實現(xiàn)的stream(_:handle :)
添加到擴展名:
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
switch eventCode {
case .hasBytesAvailable:
print("new message received")
case .endEncountered:
print("new message received")
case .errorOccurred:
print("error occurred")
case .hasSpaceAvailable:
print("has space available")
default:
print("some other event...")
}
}
1. Handling the Incoming Messages
在這里蛋欣,您已經(jīng)準(zhǔn)備好對與Stream
相關(guān)的傳入事件做些什么拉盾。 您真正感興趣的事件是.hasBytesAvailable
,因為它表示有一條要傳入的消息要讀取豁状。
接下來捉偏,您將編寫一個方法來處理這些傳入的消息。 在您剛添加的方法下方泻红,添加:
private func readAvailableBytes(stream: InputStream) {
//1
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: maxReadLength)
//2
while stream.hasBytesAvailable {
//3
let numberOfBytesRead = inputStream.read(buffer, maxLength: maxReadLength)
//4
if numberOfBytesRead < 0, let error = stream.streamError {
print(error)
break
}
// Construct the Message object
}
}
- 1) 首先夭禽,設(shè)置一個緩沖區(qū),您可以在其中讀取傳入的字節(jié)谊路。
- 2) 接下來讹躯,只要輸入流具有要讀取的字節(jié),就會循環(huán)缠劝。
- 3) 在每一點上潮梯,您將調(diào)用
read(_:maxLength :)
,它將從流中讀取字節(jié)并將它們放入您傳入的緩沖區(qū)中惨恭。 - 4) 如果對
read
的調(diào)用返回負(fù)值秉馏,則會發(fā)生一些錯誤并退出。
您需要在輸入流具有可用字節(jié)的情況下調(diào)用此方法脱羡,因此請在stream(_:handle :)
中的switch
語句中轉(zhuǎn)到.hasBytesAvailable
萝究,并在print
語句下面調(diào)用您正在處理的方法。
readAvailableBytes(stream: aStream as! InputStream)
在這一點上锉罐,你有一個充滿字節(jié)的甜蜜緩沖區(qū)帆竹!
在完成此方法之前,您需要編寫另一個幫助程序以將buffer
轉(zhuǎn)換為Message
對象脓规。
將以下方法定義放在readAvailableBytes(stream :)
下面栽连。
private func processedMessageString(buffer: UnsafeMutablePointer<UInt8>,
length: Int) -> Message? {
//1
guard
let stringArray = String(
bytesNoCopy: buffer,
length: length,
encoding: .utf8,
freeWhenDone: true)?.components(separatedBy: ":"),
let name = stringArray.first,
let message = stringArray.last
else {
return nil
}
//2
let messageSender: MessageSender =
(name == self.username) ? .ourself : .someoneElse
//3
return Message(message: message, messageSender: messageSender, username: name)
}
- 1) 首先,使用傳入的緩沖區(qū)
buffer
和長度length
初始化String
侨舆。將文本視為UTF-8
秒紧,告訴String
在完成文本時釋放字節(jié)緩沖區(qū)然后將傳入消息拆分為:character
舷暮,這樣你可以將發(fā)件人的姓名和消息視為單獨的字符串。 - 2) 接下來噩茄,您將確定您或其他人是否根據(jù)姓名發(fā)送了消息下面。 在生產(chǎn)應(yīng)用程序中,您需要使用某種唯一的
token
绩聘,但就目前而言沥割,這已經(jīng)足夠了。 - 3) 最后凿菩,使用您收集的部分構(gòu)造一條消息并將其返回机杜。
要使用Message
構(gòu)造方法,請在readAvailableBytes(stream :)
中衅谷,在最后一條注釋的正下方將以下if-let
添加到while
循環(huán)的末尾:
if let message =
processedMessageString(buffer: buffer, length: numberOfBytesRead) {
// Notify interested parties
}
到這里以后椒拗,你們都準(zhǔn)備將Message
傳遞給某人......但是誰呢?
2. Creating the ChatRoomDelegate Protocol
好吧获黔,你真的想告訴ChatRoomViewController.swift
關(guān)于新消息蚀苛,但你沒有對它的引用。 由于它擁有對ChatRoom
的強引用玷氏,因此您不希望顯式創(chuàng)建循環(huán)依賴關(guān)系并創(chuàng)建ChatRoomViewController
堵未。
這是設(shè)置代理協(xié)議的最佳時機。 ChatRoom
不關(guān)心什么樣的對象想知道新消息盏触,它只是想告訴別人渗蟹。
在ChatRoom.swift
的頂部,添加簡單的協(xié)議定義:
protocol ChatRoomDelegate: class {
func received(message: Message)
}
接下來赞辩,在ChatRoom
類的頂部雌芽,添加一個弱的可選屬性來保存對任何人決定成為ChatRoom
委托的引用:
weak var delegate: ChatRoomDelegate?
現(xiàn)在,您可以返回ChatRoom.swift
并通過為message
在if-let
中添加以下內(nèi)容來完成readAvailableBytes(stream :)
辨嗽,方法中的最后一條注釋下方:
delegate?.received(message: message)
要完成世落,請返回ChatRoomViewController.swift
并添加以下擴展名,該擴展名符合此協(xié)議召庞,位于MessageInputDelegate
下方:
extension ChatRoomViewController: ChatRoomDelegate {
func received(message: Message) {
insertNewMessageCell(message)
}
}
入門項目包括其余的管道岛心,因此insertNewMessageCell(_ :)
將接收您的消息并將適當(dāng)?shù)膯卧裉砑拥奖碇小?/p>
現(xiàn)在,通過在viewWillAppear(_ :)
中調(diào)用super
之后立即添加以下行篮灼,將視圖控制器指定為chatRoom
的代理:
chatRoom.delegate = self
再次構(gòu)建并運行您的應(yīng)用并在text field
中輸入您的名字,然后點按return
徘禁。
??聊天室現(xiàn)在成功顯示一個單元格诅诱,說明您已進入房間。 您已經(jīng)正式向基于socket
的TCP
服務(wù)器發(fā)送消息并從其接收消息送朱。
Sending Messages
現(xiàn)在您已經(jīng)設(shè)置了ChatRoom
來發(fā)送和接收消息娘荡,現(xiàn)在是時候允許用戶來回發(fā)送實際文本了干旁。
在ChatRoom.swift
中,將以下方法添加到類定義的底部:
func send(message: String) {
let data = "msg:\(message)".data(using: .utf8)!
_ = data.withUnsafeBytes {
guard let pointer = $0.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
print("Error joining chat")
return
}
outputStream.write(pointer, maxLength: data.count)
}
}
這個方法就像你之前寫的joinChat(username :)
炮沐,除了它將msg
添加到你發(fā)送的文本以表示為實際消息争群。
由于您想在inputBar
告訴ChatRoomViewController
用戶已點擊Send
時發(fā)送消息,請返回ChatRoomViewController.swift
并找到MessageInputDelegate
大年。
在這里换薄,您將看到一個名為sendWasTapped(message :)
的空方法,該方法在此時被調(diào)用翔试。 要發(fā)送消息轻要,請將其傳遞給chatRoom
:
chatRoom.send(message: message)
這就完成了全部! 由于服務(wù)器將收到此消息垦缅,然后將其轉(zhuǎn)發(fā)給所有人冲泥,因此ChatRoom
會以與您加入房間時相同的方式收到新消息的通知。
構(gòu)建并運行您的應(yīng)用程序壁涎,然后繼續(xù)為自己嘗試消息傳遞凡恍。
如果您想看到有人聊天,請轉(zhuǎn)到新的終端窗口并輸入:
nc localhost 80
這將允許您在命令行上連接到TCP
服務(wù)器怔球。 現(xiàn)在咳焚,您可以發(fā)出應(yīng)用程序用于在那里聊天的相同命令。
iam:gregg
然后庞溜,發(fā)送一個消息:
msg:Ay mang, wut's good?
恭喜革半,你已經(jīng)成功寫了一個聊天客戶端!
Cleaning up After Yourself
如果您曾對文件進行過任何編程流码,那么您應(yīng)該知道好的習(xí)慣是在完成文件后會close files又官。 事實證明Unix
通過文件句柄代表一個開放的套接字連接,就像其他一切一樣漫试。 這意味著你需要在完成后關(guān)閉它六敬,就像任何其他文件一樣。
為此驾荣,在ChatRoom.swift
中定義send(message :)
后添加以下方法:
func stopChatSession() {
inputStream.close()
outputStream.close()
}
正如您可能已經(jīng)猜到的那樣外构,這會關(guān)閉流并使其無法發(fā)送或接收信息。 這些調(diào)用還會從您之前調(diào)度的運行循環(huán)中刪除流播掷。
要完成這項任務(wù)审编,請將此方法調(diào)用添加到stream(_:handle :)
內(nèi)的switch
語句中的.endEncountered
案例中:
stopChatSession()
然后,返回ChatRoomViewController.swift
并將相同的行添加到viewWillDisappear(_ :)
:
chatRoom.stopChatSession()
這樣就全部完成了歧匈。
現(xiàn)在你已經(jīng)掌握了(或者至少看過一個簡單的例子)與套接字聯(lián)網(wǎng)的基礎(chǔ)知識垒酬,有幾個地方可以擴展你的視野。
UDP Sockets
這個iOS流教程是使用TCP
進行通信的一個示例,它打開了一個連接勘究,并保證數(shù)據(jù)包將盡可能到達目的地矮湘。
或者,您也可以使用UDP或數(shù)據(jù)報套接字進行通信口糕。這些套接字無法保證數(shù)據(jù)包將到達缅阳,這意味著它們的速度更快,開銷也更少景描。
它們對游戲等應(yīng)用非常有用十办。曾經(jīng)歷過滯后?這意味著你的連接不良伏伯,你應(yīng)該收到的很多UDP數(shù)據(jù)包都會被丟棄橘洞。
WebSockets
對這樣的應(yīng)用程序使用HTTP
的另一種替代方法是稱為WebSockets
的技術(shù)。
與傳統(tǒng)的TCP
套接字不同说搅,WebSocket
至少與HTTP
保持關(guān)系炸枣,并且可以實現(xiàn)與傳統(tǒng)套接字相同的實時通信目標(biāo),所有這些都來自瀏覽器的舒適性和安全性弄唧。
當(dāng)然适肠,您也可以將WebSockets
與iOS應(yīng)用程序一起使用。
Beej's Guide to Network Programming
最后候引,如果您真的想深入了解網(wǎng)絡(luò)侯养,請查看免費在線書籍Beej的網(wǎng)絡(luò)編程指南Beej's Guide to Network Programming。
本書提供了有關(guān)套接字編程的詳盡解釋澄干。如果你害怕C
逛揩,那么這本書可能有點令人生畏,但話又說回來麸俘,也許今天是你面對恐懼的那一天辩稽。
后記
本篇主要講述了基于Socket和TCP網(wǎng)絡(luò)的實時聊天信息流的實現(xiàn),感興趣的給個贊或者關(guān)注~~~