2015-11-16 67 views
1

我一直在嘗試在swift中編寫一個簡單的TCP/IP服務器,但我無法想出一個解決方案。我已經嘗試過在這裏和網上其他地方搜索,但我找不到適用於我正在使用的最新版本的快速版本:swift中的基本tcp/ip服務器

Apple Swift 2.1版(swiftlang-700.1。 101.6鐺-700.1.76)

目標:x86_64的-蘋果darwin14.5.0

操作系統:

的Mac OS X 10.10.5 Yosemitte

下面的代碼已經被製成,它是基於這樣一個:Socket Server Example with Swift

import Foundation 

var sock_fd: Int32 
var server_addr_size: Int 

sock_fd = socket(AF_INET, SOCK_STREAM, 0); 
if sock_fd == -1 { 
    print("Failure: creating socket") 
    exit(EXIT_FAILURE) 
} 
server_addr_size = sizeof(sockaddr_in) 
var server_addr = NSMutableData(length: server_addr_size)! 
memset(UnsafeMutablePointer<Void>(server_addr.mutableBytes), 0, server_addr_size) 
var addr = UnsafeMutablePointer<sockaddr_in>(server_addr.mutableBytes) 
addr.memory.sin_len = __uint8_t(server_addr_size) 
addr.memory.sin_family = sa_family_t(AF_INET) // chooses IPv4 
addr.memory.sin_port = 12321 // chooses the port 

let bind_server = bind(sock_fd, UnsafePointer<sockaddr>(server_addr.mutableBytes), socklen_t(server_addr_size)) 

if bind_server == -1 { 
    print("Failure: binding port") 
    exit(EXIT_FAILURE) 
} 

if listen(sock_fd, 5) == -1 { 
    print("Failure: listening") 
    exit(EXIT_FAILURE) 
} 
var client_addr = NSMutableData(length: server_addr_size)! 
memset(UnsafeMutablePointer<Void>(client_addr.mutableBytes), 0, server_addr_size) 
let client_fd = accept(sock_fd, UnsafeMutablePointer<sockaddr>(client_addr.mutableBytes), UnsafeMutablePointer<socklen_t>(bitPattern: server_addr_size)) 

if client_fd == -1 { 
    print("Failure: accepting connection") 
    exit(EXIT_FAILURE); 
} 

呼叫接受,因爲它可以通過所提到的代碼的輸出中可以看到失敗:

失敗:接受連接

程序以退出碼結束:1

除了幫助修復代碼之外,我還想知道如何讀寫連接。

謝謝,

ģOliveira的

+0

您還需要輸出'strerror(errno)'來查看accept()失敗的原因。 –

+0

感謝您的建議,這使得它更容易識別問題。 –

回答

4

UnsafeMutablePointer<socklen_t>(bitPattern: server_addr_size) 

您正在重新解釋一個整數變量作爲一個指針。這使得在運行時沒有 感知和崩潰,因爲變量的內容確實不是 指向有效的內存。 accept()函數期望這裏的socklen_t類型的變量的地址

還有其他問題,例如在套接字地址的端口號必須是big-endian字節順序:

server_addr.sin_port = UInt16(12321).bigEndian // chooses the port 

否則你的程序監聽端口8496,而不是12321.

使用NSMutableData是不是真的有必要,因爲雨燕1.2,你可以 創建sockaddr_in結構設置爲零 簡單地與所有元素:

var server_addr = sockaddr_in() 

然後withUnsafePointer()可以用來獲取IP地址到結構。

如果系統調用失敗,則將全局變量errno設置爲非零值,指示錯誤的原因。perror()可用於打印對應於errno的錯誤消息。

您可能需要設置SO_REUSEADDR套接字選項避免 「地址已在使用」錯誤綁定套接字時,看到 Uses of SO_REUSEADDR?Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems?以獲取更多信息。

這裏是你的代碼如預期在我的測試 其作品的清理後的版本:

let sock_fd = socket(AF_INET, SOCK_STREAM, 0); 
if sock_fd == -1 { 
    perror("Failure: creating socket") 
    exit(EXIT_FAILURE) 
} 

var sock_opt_on = Int32(1) 
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &sock_opt_on, socklen_t(sizeofValue(sock_opt_on))) 

var server_addr = sockaddr_in() 
let server_addr_size = socklen_t(sizeofValue(server_addr)) 
server_addr.sin_len = UInt8(server_addr_size) 
server_addr.sin_family = sa_family_t(AF_INET) // chooses IPv4 
server_addr.sin_port = UInt16(12321).bigEndian // chooses the port 

let bind_server = withUnsafePointer(&server_addr) { 
    bind(sock_fd, UnsafePointer($0), server_addr_size) 
} 
if bind_server == -1 { 
    perror("Failure: binding port") 
    exit(EXIT_FAILURE) 
} 

if listen(sock_fd, 5) == -1 { 
    perror("Failure: listening") 
    exit(EXIT_FAILURE) 
} 

var client_addr = sockaddr_storage() 
var client_addr_len = socklen_t(sizeofValue(client_addr)) 
let client_fd = withUnsafeMutablePointer(&client_addr) { 
    accept(sock_fd, UnsafeMutablePointer($0), &client_addr_len) 
} 
if client_fd == -1 { 
    perror("Failure: accepting connection") 
    exit(EXIT_FAILURE); 
} 

print("connection accepted") 

read()write()系統調用,然後使用從 讀取和寫入到接受的套接字。

1

對於那些誰來到這個話題尋找關於同一主題的一些幫助,除了馬丁的回答,我提出,下面,我如何看一個小例子,寫/從插座:

// reading one char at a time 
var buff_rcvd = CChar() 
read(client_fd, &buff_rcvd, 1) 
print(NSString(format:"Received: *%c*",buff_rcvd)) 

// writing one chat at a time 
var buff_send: CChar = 65 // character "A" defined as CChar 
write(client_fd, &buff_send, 1) 
print(NSString(format:"Sent: *%c*",buff_send)) 

和代碼完成後,我們一定不要忘記關閉連接:

close(sock_fd) 
close(client_fd) 
1

只是一個小更新斯威夫特4.

import Foundation 

let sock_fd = socket(AF_INET, SOCK_STREAM, 0); 
if sock_fd == -1 { 
    perror("Failure: creating socket") 
    exit(EXIT_FAILURE) 
} 

var sock_opt_on = Int32(1) 
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &sock_opt_on, socklen_t(MemoryLayout.size(ofValue: sock_opt_on))) 

var server_addr = sockaddr_in() 
let server_addr_size = socklen_t(MemoryLayout.size(ofValue: server_addr)) 
server_addr.sin_len = UInt8(server_addr_size) 
server_addr.sin_family = sa_family_t(AF_INET) // chooses IPv4 
server_addr.sin_port = UInt16(12321).bigEndian // chooses the port 

let bind_server = withUnsafePointer(to: &server_addr) { 
    bind(sock_fd, UnsafeRawPointer($0).assumingMemoryBound(to: sockaddr.self), server_addr_size) 
} 
if bind_server == -1 { 
    perror("Failure: binding port") 
    exit(EXIT_FAILURE) 
} 

if listen(sock_fd, 5) == -1 { 
    perror("Failure: listening") 
    exit(EXIT_FAILURE) 
} 

var client_addr = sockaddr_storage() 
var client_addr_len = socklen_t(MemoryLayout.size(ofValue: client_addr)) 
let client_fd = withUnsafeMutablePointer(to: &client_addr) { 
    accept(sock_fd, UnsafeMutableRawPointer($0).assumingMemoryBound(to: sockaddr.self), &client_addr_len) 
} 
if client_fd == -1 { 
    perror("Failure: accepting connection") 
    exit(EXIT_FAILURE); 
} 
+0

很好!你測試過了嗎? –

+0

是的,我還沒有在4.1中檢查過。 – rougeExciter