Issue sending data from Objective-C server to swift client

I’m working on a learning project where I’m trying to create a websocket server on macOS using objective-C and a client using swift. I’m able to send message from client to server and it’s getting through fine. After receiving a message on server, I want to send a message back to client. Message is UTF8 encoded. But I’m receiving some receiving garbled text on client(raw data not matching). Now 2 questions –
1)I can’t pin point as to where I’m making the mistake.
2)If there is a better way to build something like this?

Server side code


#import <Foundation/Foundation.h>
#import <Network/Network.h>

@interface WebSocketServer : NSObject

@property (nonatomic, retain) nw_listener_t listener;
@property (nonatomic, strong) NSNetService *netService;

- (void)startServerOnPort:(uint16_t)port;

@end

@implementation WebSocketServer

- (void)startServerOnPort:(uint16_t)port {
    
    //configure connection parameters such as tcp, udp and whether you want tls or not
    nw_parameters_configure_protocol_block_t configure_tls = NW_PARAMETERS_DISABLE_PROTOCOL;
    nw_parameters_t parameters = nw_parameters_create_secure_tcp(
                                    configure_tls,
                                    NW_PARAMETERS_DEFAULT_CONFIGURATION
                                );
    //create a listener on a specific port
    self.listener = nw_listener_create_with_port([NSString stringWithFormat:@"%d", port].UTF8String, parameters);
    //set a queue
    nw_listener_set_queue(self.listener, dispatch_get_main_queue());
    //set state change handler
    nw_listener_set_state_changed_handler(self.listener, ^(nw_listener_state_t state, nw_error_t error) {
//        … your state changed handler …
        switch (state) {
                /*! @const nw_listener_state_invalid The state of the listener is not valid. This state will never be delivered in the listener's state update handler, and can be treated as an unexpected value. */
            case nw_listener_state_invalid:
                NSLog(@"nw_listener_set_state_changed_handler:nw_listener_state_invalid");
                break;
                /*! @const nw_listener_state_waiting The listener is waiting for a usable network before being able to receive connections */
            case nw_listener_state_waiting:
                NSLog(@"nw_listener_set_state_changed_handler:nw_listener_state_waiting");
                break;
                /*! @const nw_listener_state_ready The listener is ready and able to accept incoming connections */
            case nw_listener_state_ready:
                NSLog(@"nw_listener_set_state_changed_handler:nw_listener_state_ready");
                break;
                /*! @const nw_listener_state_failed The listener has irrecoverably closed or failed */
            case nw_listener_state_failed:
                NSLog(@"nw_listener_set_state_changed_handler:nw_listener_state_failed");
                break;
                /*! @const nw_listener_state_cancelled The listener has been cancelled by the caller */
            case nw_listener_state_cancelled:
                NSLog(@"nw_listener_set_state_changed_handler:nw_listener_state_cancelled");
                break;
            default:
                break;
        }
    });
    //set new connection handler
    nw_listener_set_new_connection_handler(self.listener, ^(nw_connection_t connection) {
        NSLog(@"New connection received");
        nw_connection_set_queue(connection, dispatch_get_main_queue());
        nw_connection_set_state_changed_handler(connection, ^(nw_connection_state_t state, nw_error_t  _Nullable error) {
            switch (state) {
                    /*! @const nw_connection_state_invalid The state of the connection is not valid. This state will never be delivered in the connection's state update handler, and can be treated as an unexpected value. */
                case nw_connection_state_invalid:
                    NSLog(@"nw_listener_set_new_connection_handler:nw_connection_state_invalid");
                    break;
                    /*! @const nw_connection_state_waiting The connection is waiting for a usable network before re-attempting */
                case nw_connection_state_waiting:
                    NSLog(@"nw_listener_set_new_connection_handler:nw_connection_state_waiting");
                    break;
                    /*! @const nw_connection_state_preparing The connection is in the process of establishing */
                case nw_connection_state_preparing:
                    NSLog(@"nw_listener_set_new_connection_handler:nw_connection_state_preparing");
                    break;
                    /*! @const nw_connection_state_ready The connection is established and ready to send and receive data upon */
                case nw_connection_state_ready:
                    NSLog(@"nw_listener_set_new_connection_handler:nw_connection_state_ready");
                    [self logClientDetails:connection];
                    [self receiveMessageOnConnection:connection];
                    
                    break;
                    /*! @const nw_connection_state_failed The connection has irrecoverably closed or failed */
                case nw_connection_state_failed:
                    NSLog(@"nw_listener_set_new_connection_handler:nw_connection_state_failed");
                    break;
                    /*! @const nw_connection_state_cancelled The connection has been cancelled by the caller */
                case nw_connection_state_cancelled:
                    NSLog(@"nw_listener_set_new_connection_handler:nw_connection_state_cancelled");
                    break;
                default:
                    NSLog(@"nw_listener_set_new_connection_handler:default");
                    break;
            }
        });
        NSLog(@"Starting connection");
        nw_connection_start(connection);
    });
    //start listening
    nw_listener_start(self.listener);
}
- (void)logClientDetails:(nw_connection_t)connection {
    nw_endpoint_t endpoint = nw_connection_copy_endpoint(connection);
    if (nw_endpoint_get_type(endpoint) == nw_endpoint_type_host) {
        const char *hostname = nw_endpoint_get_hostname(endpoint);
        const char *port = nw_endpoint_copy_port_string(endpoint);
        NSLog(@"Client connected from %s:%s", hostname, port);
        free((void *)hostname);  // If needed to free, but usually ARC should handle
        free((void *)port);  // If needed to free, but usually ARC should handle
    }
}


- (void)receiveMessageOnConnection:(nw_connection_t)connection {
    nw_connection_receive(connection, 1, UINT32_MAX, ^(dispatch_data_t content, nw_content_context_t context, bool is_complete, nw_error_t receive_error) {
        if (content) {
            const void *buffer;
            size_t buffer_size;
            dispatch_data_t data = dispatch_data_create_map(content, &buffer, &buffer_size);
            NSString *message = [[NSString alloc] initWithBytes:buffer length:buffer_size encoding:NSUTF8StringEncoding];
            NSLog(@"Received message: %@", message);
            [self sendMessage:@"Message received" onConnection:connection];
            // Respond to message if needed
            [self receiveMessageOnConnection:connection]; // Continue receiving more messages
        } else if (receive_error) {
            NSLog(@"Failed to receive message with error: %@", receive_error);
        }
    });
}

- (void)sendMessage:(NSString *)message onConnection:(nw_connection_t)connection {
    NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
    dispatch_data_t content = dispatch_data_create(data.bytes, data.length, dispatch_get_main_queue(), ^{
           // No-op
       });
    
    // Log the raw data in hexadecimal format
        NSMutableString *hexString = [NSMutableString stringWithCapacity:data.length * 2];
        const unsigned char *dataBytes = (const unsigned char *)data.bytes;
        for (NSInteger i = 0; i < data.length; i++) {
            [hexString appendFormat:@"%02x", dataBytes[i]];
        }
        NSLog(@"Raw data to be sent: %@", hexString);
    
    nw_connection_send(connection, content, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^(nw_error_t  _Nullable send_error) {
        if (send_error) {
            NSLog(@"Failed to send message with error: %@", send_error);
        } else {
            NSLog(@"Message sent: %@", message);
        }
    });
}

@end

WebSocketServer *server = [[WebSocketServer alloc] init];
uint16_t port = 12345;
[server startServerOnPort:port];

[[NSRunLoop currentRunLoop] run]; // Keep the application running

Server side console logs

2024-05-25 23:45:28.693748+0530 WebSocketServerAppObjectiveC[89294:2585208] nw_listener_set_state_changed_handler:nw_listener_state_ready
2024-05-25 23:45:30.297234+0530 WebSocketServerAppObjectiveC[89294:2585208] New connection received
2024-05-25 23:45:30.297275+0530 WebSocketServerAppObjectiveC[89294:2585208] Starting connection
2024-05-25 23:45:30.297506+0530 WebSocketServerAppObjectiveC[89294:2585208] nw_listener_set_new_connection_handler:nw_connection_state_preparing
2024-05-25 23:45:30.297699+0530 WebSocketServerAppObjectiveC[89294:2585208] nw_listener_set_new_connection_handler:nw_connection_state_ready
2024-05-25 23:45:30.297896+0530 WebSocketServerAppObjectiveC[89294:2585208] Received message: Hello, server!
2024-05-25 23:45:30.297934+0530 WebSocketServerAppObjectiveC[89294:2585208] Raw data to be sent: 4d657373616765207265636569766564
2024-05-25 23:45:30.298040+0530 WebSocketServerAppObjectiveC[89294:2585208] Message sent: Message received

Client side code

import Foundation
import Network

class WebSocketClient {
    var connection: NWConnection?
    
    func startConnection(to host: String, port: UInt16) {
        let parameters = NWParameters.tcp
        let endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(host), port: NWEndpoint.Port(rawValue: port)!)
        
        connection = NWConnection(to: endpoint, using: parameters)
        
        connection?.stateUpdateHandler = { state in
            switch state {
            case .ready:
                print("Client connection ready")
                self.sendMessage("Hello, server!")
                self.receiveMessage()
            case .failed(let error):
                print("Client connection failed: (error)")
            case .waiting(let error):
                print("Client connection waiting: (error)")
            case .cancelled:
                print("Client connection cancelled")
            default:
                break
            }
        }
        
        connection?.start(queue: .main)
    }
    
    func sendMessage(_ message: String) {
        guard let connection = connection else { return }
        let data = message.data(using: .utf8)!
        
        connection.send(content: data, completion: .contentProcessed { error in
            if let error = error {
                print("Failed to send message: (error)")
            } else {
                print("Message sent")
            }
        })
    }
    
    func receiveMessage() {
            guard let connection = connection else { return }
            
        connection.receive(minimumIncompleteLength: 1, maximumLength: Int(UInt32.max)) { [weak self]data, context, isComplete, error in
            guard let weakSelf = self else { return }
                if let data = data, !data.isEmpty {
                    
                    let rawData = data.map { String(format: "%02x", $0) }.joined()
                    print("Received raw data: (rawData)")
                    if let message = String(data: data, encoding: .utf8) {
                        print("Received message: (message)")
                        // Continue to receive more messages
                        weakSelf.receiveMessage()
                    } else {
                        print("Failed to decode received message as UTF-8")
                    }
                    
                }
                if let error = error {
                    print("Failed to receive message: (error)")
                }
            }
        }
    func stopConnection() {
        connection?.cancel()
    }
}

let client = WebSocketClient()
client.startConnection(to: "localhost", port: 12345)

RunLoop.main.run()

Client side console logs

Client connection ready
Message sent
Received raw data: d8fda4a2018017445cd572f201000000
Failed to decode received message as UTF-8

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật