Socket Server Example with Swift
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)
Admin
Updated on June 05, 2022Comments
-
Admin almost 2 years
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) }
-
Martin R almost 10 yearsThere are actually more problems in your code. For example
buff_snd
is a SwiftString
. You cannot simply treat that as achar
buffer inwrite(client_socket, &buff_snd, strlen(buff_snd) + 1)
. -
János almost 9 yearsMartin, 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
-
Martin R almost 9 years@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.