11

I tried to make an example of simple socket server.

Build and run successfully. However it doesn't work well.

Client couldn't connect to this server.

How to solve this problem? I need your help, thanks.

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)
}
3
  • have you cleaned up your code? I would use it also, I get an error at this line: let struct_pointer = UnsafePointer<S>.alloc(1) does not have a member named alloc Commented May 15, 2015 at 12:04
  • This thread is rather old, but for anyone coming here looking for an up-to-date Swift socket package this might be what you want: github.com/IBM-Swift/BlueSocket Commented Jan 27, 2017 at 5:47
  • Another possibility is this one: github.com/Balancingrock/SwifterSockets Commented Jan 28, 2017 at 16:13

2 Answers 2

4

The port number in the socket address must be in big-endian byte order:

server_addr.sin_port = UInt16(4000).bigEndian

So your program actually listens on port 40975 (hex 0xA00F) and not on port 4000 (hex 0x0FA0).

Another problem is here:

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

Your buffer is an empty array, but recv() expects a buffer of size BUFF_SIZE. The behaviour is undefined. To get a buffer of the required size, use

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

Remark: Here you cast the address of an Int to the address of an socklen_t and pass that to the accept() function:

client_socket = accept(server_socket, sockaddr_cast(&client_addr), socklen_t_cast(&client_addr_size))

That is not safe. If Int and socklen_t have different sizes then the behaviour will be undefined. You should declare server_addr_size and client_addr_size as socklen_t and remove the socklen_t_cast() function:

client_socket = accept(server_socket, sockaddr_cast(&client_addr), &client_addr_size)
Sign up to request clarification or add additional context in comments.

3 Comments

There are actually more problems in your code. For example buff_snd is a Swift String. You cannot simply treat that as a char buffer in write(client_socket, &buff_snd, strlen(buff_snd) + 1).
Martin, could you recommend an easy implementation of socket server implemented in Swift that receives and responds strings? socket tutorial below claims, that only 4 method should be implemented, (socket, bind, listen, accept) but all the solution I checked out in SO and github are are so complex, differs from each other and overcomplicated cs.rpi.edu/~moorthy/Courses/os98/Pgms/socket.html
@János: Server socket programming isn't easy (at least if you want to handle multiple connections concurrently). GCDAsyncSocket (github.com/robbiehanson/CocoaAsyncSocket) is a nice wrapper written in Objective-C and can be used from Swift, but I do not have any recommendation.
0

As Martin R commented before, the write command shouldn't be using the swift string as that. Something like this will work properly:

write(client_socket, buff_snd.cStringUsingEncoding(NSUTF8StringEncoding)!, countElements(buff_snd) + 1)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.