JavaScript로 서버를 구현하고, Swift로 클라이언트를 구현해서 Socket.IO를 이용해 데이터를 주고 받는 과정에서 엄청 고생을 했다.
그래서 서버와 클라이언트 간에 데이터를 주고받는 방법을 정리하려고 한다!
보낼 때
String 타입의 데이터는 클라이언트에서 별다른 처리 없이 바로 전송할 수 있고, 데이터를 받을 때는 아래와 같이 처리한다.
let stringData = "한솔"
socket.emit(SocketEvent.test.rawValue, stringData)
받을 때
서버로부터 수신된 데이터가 포함된 배열인 data를 String 타입으로 타입캐스팅해서 사용한다.
socket.on("test") { data, ack in
if let message = data[0] as? String {
print("서버에서 받은 데이터: \(message)")
}
}
// 서버에서 받은 데이터: 한솔
서버에서도 클라이언트로부터 String 데이터를 받아서 그대로 다시 보낼 수 있다.
socket.on('test', stringData => {
console.log(stringData); // 한솔
socket.emit('test', stringData);
});
보낼 때
let arrayData = ["한", "솔"]
socket.emit(SocketEvent.test.rawValue, arrayData)
받을 때
socket.on("test") {data, ack in
if let message = data[0] as? [String] {
for i in message {
print("서버에서 받은 데이터 :", i)
}
}
}
// 서버에서 받은 데이터 : 한
// 서버에서 받은 데이터 : 솔
socket.on('test', arrayData => {
console.log(arrayData); // ['한', '솔']
socket.emit('test', arrayData)
});
보낼 때
let dictionaryData = ["name" : "한솔"]
socket.emit(SocketEvent.test.rawValue, dictionaryData)
받을 때
socket.on("test") { data, ack in
if let dict = data[0] as? [String: Any],
let name = dict["name"] as? String {
print("서버에서 받은 데이터: \(name)")
}
}
// 서버에서 받은 데이터: 한솔
socket.on('test', dicData => {
console.log(dicData); // { name: '한솔' }
socket.emit('test', dicData)
});
보낼 때
클라이언트에서 객체를 서버에 전송하려면 해당 객체가 SocketData 프로토콜을 준수해야 한다. SocketData 프로토콜을 준수해야 객체가 소켓을 통해 전송 가능한 형태로 변환될 수 있다.
// Model
struct Chat: SocketData {
let message: String
let sender: String
// SocketData 프로토콜 준수
func socketRepresentation() -> SocketData {
return ["message": message, "sender": sender]
}
}
// 서버에 보내는 코드
let chatData = Chat(message: "안녕", sender: "한솔")
socket.emit(SocketEvent.test.rawValue, chatData)
받을 때
SocketData 프로토콜을 준수하기 때문에 객체 그대로 서버에 전송해도,서버에서 다시 받을 때는 딕셔너리 형태로 받아야한다.
socket.on(SocketEvent.test.rawValue) { data, ack in
if let dict = data[0] as? [String: Any],
let message = dict["message"] as? String,
let sender = dict["sender"] as? String {
let receivedChat = Chat(message: message, sender: sender)
print("서버에서 받은 데이터: \(receivedChat)")
}
}
// 서버에서 받은 데이터: Chat(message: "안녕", sender: "한솔")
클라이언트에서 전송한 객체가 SocketData 프로토콜을 준수하기 때문에 딕셔너리 형태로 전송된다. 받은 딕셔너리를 개별 변수로 사용하거나, 딕셔너리 자체를 사용할 수도 있다.
socket.on('test', (data) => {
const { message, sender } = data;
console.log(message, sender); // 안녕 한솔
socket.emit('test', message)
});
socket.on('test', (data) => {
console.log(data); // { sender: '한솔', message: '안녕' }
socket.emit('test', data)
});
보낼 때
객체 배열을 딕셔너리 배열로 변환하여 전송해야한다.
let chatDatas = [Chat(message: "안녕", sender: "한솔"),
Chat(message: "빠잉", sender: "한솔")]
let chatArray = chatDatas.map { $0.socketRepresentation() }
socket.emit(SocketEvent.test.rawValue, chatArray)
받을 때
data를 [[String: Any]] 타입의 배열로 다운캐스팅한다.
각각의 요소가 [String: Any] 형식의 딕셔너리인 객체 배열을 의미한다.
다운캐스팅 한 뒤 각 딕셔너리를 Chat 객체로 변환해서 사용한다.
socket.on(SocketEvent.test.rawValue) { data, ack in
if let array = data[0] as? [[String: Any]] {
let receivedChats = array.map { dict -> Chat in
let message = dict["message"] as! String
let sender = dict["sender"] as! String
return Chat(message: message, sender: sender)
}
for chat in receivedChats {
print("서버에서 받은 데이터: \(chat.message) - \(chat.sender)")
}
}
}
서버에서 JSON 형식으로 보낸 데이터는 파싱해서 사용해야한다.
socket.on(SocketEvent.test.rawValue) { data, ack in
if let jsonDataString = data[0] as? String,
let jsonData = jsonDataString.data(using: .utf8),
let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
print("서버에서 받은 JSON 데이터: \(jsonObject)")
}
}
딕셔너리 타입의 배열 자체를 보내거나, JSON 형식으로 변환해서 보낼 수 있다.
socket.on('test', (data) => {
console.log(data); // [ { message: '안녕', sender: '한솔' }, { sender: '한솔', message: '빠잉' } ]
socket.emit('test', data)
});
socket.on('test', (data) => {
console.log(data);
// 데이터를 JSON 형식으로 변환
const jsonData = JSON.stringify(data);
socket.emit('test', jsonData);
});