2015-11-16 41 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