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.
//
// 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.