Swift的套接字服务器示例

ste*_*lee 11 sockets macos swift

我试着做一个简单套接字服务器的例子.

构建并成功运行.但它不能很好地工作.

客户端无法连接到此服务器.

如何解决这个问题呢?我需要你的帮助,谢谢.

import Foundation

let BUFF_SIZE = 1024

func initStruct<S>() -> S {
    let struct_pointer = UnsafePointer<S>.alloc(1)
    let struct_memory = struct_pointer.memory
    struct_pointer.destroy()
    return struct_memory
}

func sockaddr_cast(p: ConstUnsafePointer<sockaddr_in>) -> UnsafePointer<sockaddr> {
    return UnsafePointer<sockaddr>(p)
}

func socklen_t_cast(p: UnsafePointer<Int>) -> UnsafePointer<socklen_t> {
    return UnsafePointer<socklen_t>(p)
}

var server_socket: Int32
var client_socket: Int32
var server_addr_size: Int
var client_addr_size: Int

var server_addr: sockaddr_in = initStruct()
var client_addr: sockaddr_in = initStruct()

var buff_rcv: Array<CChar> = []
var buff_snd: String

server_socket = socket(PF_INET, SOCK_STREAM, 0);

if server_socket == -1
{
    println("[Fail] Create Server Socket")
    exit(1)
}
else
{
    println("[Success] Created Server Socket")
}

server_addr_size = sizeof(server_addr.dynamicType)
memset(&server_addr, 0, UInt(server_addr_size));

server_addr.sin_family = sa_family_t(AF_INET)
server_addr.sin_port = 4000
server_addr.sin_addr.s_addr = UInt32(0x00000000)    // INADDR_ANY = (u_int32_t)0x00000000 ----- <netinet/in.h>

let bind_server = bind(server_socket, sockaddr_cast(&server_addr), socklen_t(server_addr_size))

if bind_server == -1
{
    println("[Fail] Bind Port");
    exit(1);
}
else
{
    println("[Success] Binded Port");
}

if listen(server_socket, 5) == -1
{
    println("[Fail] Listen");
    exit(1);
}
else
{
    println("[Success] Listening : \(server_addr.sin_port) Port ...");
}

var n = 0

while n < 1
{
    client_addr_size = sizeof(client_addr.dynamicType)
    client_socket = accept(server_socket, sockaddr_cast(&client_addr), socklen_t_cast(&client_addr_size))

    if client_socket == -1
    {
        println("[Fail] Accept Client Connection");
        exit(1);
    }
    else
    {
        println("[Success] Accepted Client : \(inet_ntoa(client_addr.sin_addr)) : \(client_addr.sin_port)");
    }

    read(client_socket, &buff_rcv, UInt(BUFF_SIZE))

    println("[Success] Received : \(buff_rcv)")

    buff_snd = "\(strlen(buff_rcv)) : \(buff_rcv)"

    write(client_socket, &buff_snd, strlen(buff_snd) + 1)

    close(client_socket)
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*n R 4

套接字地址中的端口号必须采用大端字节顺序:

server_addr.sin_port = UInt16(4000).bigEndian
Run Code Online (Sandbox Code Playgroud)

因此,您的程序实际上侦听端口 40975(十六进制 0xA00F),而不是端口 4000(十六进制 0x0FA0)。

另一个问题在这里:

var buff_rcv: Array<CChar> = []
// ...
read(client_socket, &buff_rcv, UInt(BUFF_SIZE))
Run Code Online (Sandbox Code Playgroud)

您的缓冲区是一个数组,但recv()需要一个 size 的缓冲区BUFF_SIZE。该行为是未定义的。要获得所需大小的缓冲区,请使用

var buff_rcv = [CChar](count:BUFF_SIZE, repeatedValue:0)
// ...
read(client_socket, &buff_rcv, UInt(buff_rcv.count))
Run Code Online (Sandbox Code Playgroud)

备注:这里将 an 的地址转换Int为 an 的地址socklen_t 并将其传递给accept()函数:

client_socket = accept(server_socket, sockaddr_cast(&client_addr), socklen_t_cast(&client_addr_size))
Run Code Online (Sandbox Code Playgroud)

那不安全。如果Intsocklen_t具有不同的大小,则行为将是不确定的。您应该声明server_addr_sizeand client_addr_size assocklen_t并删除该socklen_t_cast()函数:

client_socket = accept(server_socket, sockaddr_cast(&client_addr), &client_addr_size)
Run Code Online (Sandbox Code Playgroud)