Pages

Thursday, July 16, 2020

Simple BSD Socket Client Server Example for macOS iOS

Today I am going to share about a simple Client Server example I have been working on to clear my concepts of BSD Socket. You can work on high leven APIs like CFSocket, But sometimes you need the help of a pure socket. 

I tested this code in macOS

RCDBSDServer.h

//

//  RCDServer.h

//  HelloMacObj

//

//  Created by Razib Chandra Deb on 15/7/20.

//  Copyright © 2020 Razib Chandra Deb. All rights reserved.

//


#import <Foundation/Foundation.h>


NS_ASSUME_NONNULL_BEGIN


@interface RCDBSDServer : NSObject

-(BOOL) startOnPort:(int) port;

-(void) stop;

-(void) sendString: (NSString *) string;

-(void) readData:(int) length;

@end


NS_ASSUME_NONNULL_END



RCDBSDServer.mm


//

//  RCDServer.m

//  HelloMacObj

//

//  Created by Razib Chandra Deb on 15/7/20.

//  Copyright © 2020 Razib Chandra Deb. All rights reserved.

//


#import "RCDBSDServer.h"

#include <netdb.h>

#include <netinet/in.h>

#include <sys/ioctl.h>

#include <sys/un.h>

#include <err.h>

#include <fcntl.h>

#include <arpa/inet.h>

#import <objc/runtime.h>

/*

 

 https://www.tutorialspoint.com/unix_sockets/socket_server_example.htm

Create a socket with the socket() system call.


Bind the socket to an address using the bind() system call. For a server socket on the Internet, an address consists of a port number on the host machine.


Listen for connections with the listen() system call.


Accept a connection with the accept() system call. This call typically blocks until a client connects with the server.


Send and receive data using the read() and write() system calls.

*/

@implementation RCDBSDServer {

    int sockfd, portno, n, newSockFd;

    struct sockaddr serv_addr;

    struct hostent *server;

    

    struct sockaddr_in client_addr;

    socklen_t client_addr_len;

}



-(id) init {

    self = [super init];

    if ( self != nil) {

        

    }

    return self;

}


-(BOOL) startOnPort:(int) port {

    // Connect socket

    struct sockaddr_in addr;

    bzero((char *)&addr, sizeof(addr));

    

    addr.sin_family = AF_INET;

    addr.sin_port = htons(port);

    //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

    

    socklen_t socklen = sizeof(addr);

    

    

    /* First call to socket() function */

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    

    if (sockfd < 0) {

        Log(@"[Server] socket creation failed");

        return NO;

    }

    

//    int on = 1;

//    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {

//        close(sockfd);

//        Log(@"Error on setsockopt");

//        return false;

//    }

//

//    if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {

//        close(sockfd);

//        Log(@"Error on fcntl");

//        return false;

//    }


    if (bind(sockfd, (struct sockaddr*)&addr, socklen) != 0) {

        close(sockfd);

        Log(@"Error on bind");

        return false;

    }

    

    /* Now start listening for the clients, here process will

       * go in sleep mode and will wait for the incoming connection

    */

    if (listen(sockfd, DATA_CHUNK) != 0) {

        close(sockfd);

        Log(@"Error on listen");

        return false;

    }

    else {

        Log(@"listen success");

    }

    

    client_addr_len = sizeof(client_addr);

    /* Accept actual connection from the client */

    newSockFd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);

     

    if (newSockFd < 0) {

       Log(@"ERROR on accept");

        return false;

    }

    

    /* If connection is established then start communicating */

  

    return true;

}

-(void) stop {

    close(sockfd);

}

-(void) sendString: (NSString *) string {

     const char * buffer = [string cStringUsingEncoding:NSUTF8StringEncoding];

     ssize_t n = write(newSockFd, buffer, (int) strlen(buffer));

     Log(@"[Server] Data sent %zd", n);

}

-(void) readData:(int) length {

    char data[DATA_CHUNK];

    

    memset(data, 0, DATA_CHUNK);

    ssize_t n = read(newSockFd, data, length);

    Log(@"[Server] Data read %zd Data \n%s\n", n, data);

}

@end




RCDBSDClient.h

//

//  RCDBSDClient.h

//  HelloMacObj

//

//  Created by Razib Chandra Deb on 15/7/20.

//  Copyright © 2020 Razib Chandra Deb. All rights reserved.

//


#import <Foundation/Foundation.h>


NS_ASSUME_NONNULL_BEGIN


@interface RCDBSDClient : NSObject

-(BOOL) connectToServerIp:(NSString *) ipAddres withPort:(int) port;

-(void) stop;

-(void) sendString: (NSString *) string;

-(void) readData:(int) length;

@end


NS_ASSUME_NONNULL_END



RCDBSDClient.mm

//

//  RCDBSDClient.m

//  HelloMacObj

//

//  Created by Razib Chandra Deb on 15/7/20.

//  Copyright © 2020 Razib Chandra Deb. All rights reserved.

//


#import "RCDBSDClient.h"

#include <netdb.h>

#include <netinet/in.h>

#include <sys/ioctl.h>

#include <sys/un.h>

#include <err.h>

#include <fcntl.h>

#include <arpa/inet.h>


/*

 https://www.tutorialspoint.com/unix_sockets/socket_client_example.htm

 Create a socket with the socket() system call.


 Connect the socket to the address of the server using the connect() system call.


 Send and receive data. There are a number of ways to do this, but the simplest way is to use the read() and write() system calls.

 */


@implementation RCDBSDClient {

    int sockfd, portno, n;

    struct sockaddr serv_addr;

    struct hostent *client;

}


-(id) init {

    self = [super init];

    if ( self != nil) {

        

    }

    return self;

}



-(BOOL) connectToServerIp:(NSString *) ipAddres withPort:(int) port {

    

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd == -1) {

        Log(@"Error on socket");

        return NO;

    }

    

    // prevent SIGPIPE

    int on = 1;

    setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));

    

    struct hostent *serverAddres = gethostbyname([ipAddres cStringUsingEncoding:NSUTF8StringEncoding]);

    

    // Connect socket

    struct sockaddr_in addr;


    

    bzero((char *) &addr, sizeof(addr));

    addr.sin_family = AF_INET;

    bcopy((char *)serverAddres->h_addr, (char *)&addr.sin_addr.s_addr, serverAddres->h_length);

    addr.sin_port = htons(port);

    

    socklen_t socklen = sizeof(addr);

    if (connect(sockfd, (struct sockaddr*)&addr, socklen) == -1) {

        Log(@"Error on connect");

        return NO;

    }

    

    Log(@"Connection Success");

    

    return true;

}

-(void) stop {

    close(sockfd);

}

-(void) sendString: (NSString *) string {

    const char * buffer = [string cStringUsingEncoding:NSUTF8StringEncoding];

    ssize_t n = write(sockfd, buffer, (int) strlen(buffer));

    Log(@"[Client] Data sent %zd", n);

}

-(void) readData:(int) length {

    char data[DATA_CHUNK];

    memset(data, 0, DATA_CHUNK);

    ssize_t n = read(sockfd, data, length);

    Log(@"[Client] Data read %zd Data \n%s\n", n, data);

}

@end




Please feel free to share your thoughts. 


 

No comments: