swift中的基本tcp / ip服务器

时间:2015-11-16 03:15:56

标签: swift tcp server ip

我一直试图在swift中编写一个简单的TCP / IP服务器,但我无法提出解决方案。我已经尝试过在这里和网络的其他部分进行搜索,但我找不到适用于我正在使用的最新版本的内容:

  

Apple Swift 2.1版(swiftlang-700.1.101.6 clang-700.1.76)

     

目标:x86_64-apple-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);
}

accept 的调用失败,因为它可以在上述代码给出的输出中看到:

  

失败:接受连接

     

程序以退出代码结束:1

除了修复代码的帮助外,我还想知道如何读取和写入连接。

谢谢,

G Oliveira

3 个答案:

答案 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并不是必需的,因为Swift 1.2可以 创建一个sockaddr_in结构,所有元素都设置为零 只需:

var server_addr = sockaddr_in()

然后withUnsafePointer()可用于获取结构的地址。

如果系统调用失败,则全局变量errno将设置为非零值,指示错误原因。 perror()可用于打印与errno对应的错误消息。

您可能希望设置SO_REUSEADDR套接字选项以避免 一个&#34;地址已经在使用&#34;绑定套接字时出错,请参阅 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 :(得分:3)

对Swift 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);
}

答案 2 :(得分:1)

对于那些在同一主题上寻求帮助的人,除了Martin的回答之外,我在下面提供了一个关于我如何阅读和写入套接字的小例子:

// 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)