Creating a data client
In the Creating a data server recipe of this chapter, we updated our BSDSocketServer
class so we could set up a server that could receive data. In this recipe, we will be updating our BSDSocketClient
class so we can set up a client to upload data to our data server.
Getting ready
This recipe is compatible with both iOS and OS X. No extra frameworks or libraries are required.
How to do it…
Let's update the BSDSocketClient
class to include our data client.
Since we will be able to use the same constructor (initWithAddress:andPort:
) that we used when we connected to the echo server, all we need to do is to add a method to send the data itself. This method will be called sendData:toSocket:
. The following is the new BSDSocketClient
header file:
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSUInteger, BSDClientErrorCode) {
NOERRROR,
SOCKETERROR,
CONNECTERROR,
READERROR,
WRITEERROR
};
#define MAXLINE 4096
@interface BSDSocketClient : NSObject
@property int errorCode, sockfd;
-(id)initWithAddress:(NSString *)addr andPort:(int)port;
-(ssize_t) writtenToSocket:(int)sockfdNum withChar:(NSString *)vptr;
-(NSString *) recvFromSocket:(int)lsockfd withMaxChar:(int)max;
-(ssize_t)sendData:(NSData *)data toSocket:(int)lsockfd;
@end
We now need to add the sendData:toSocket:
method to our BSDSocketClient
class:
-(ssize_t)sendData:(NSData *)data toSocket:(int)lsockfd { NSLog(@"sending"); ssize_t n; const UInt8 *buf = (const UInt8 *)[data bytes]; if ((n = send(lsockfd, buf,[data length],0)) <=0) { errorCode = WRITEERROR; return -1; } else { errorCode = NOERRROR; return n; } }
The sendData:toSocket:
method accepts two parameters: the data to send to the server and the socket descriptor to which we want to send the data. Since the BSD Socket Library does not recognize the NSData
objects, we will need to convert the data to bytes and then to a UInt8
buffer prior to sending it.
Once we have our UInt8
buffer, we use the send()
function to send the data to the server. The send()
function will return the number of bytes sent to the server; if that number is less than 0, it means there is a problem and we return an error.
Let's take a look at the sample code that uses the sendData:toSocket
method:
BSDSocketClient *bsdCli = [[BSDSocketClient alloc] initWithAddress:@"127.0.0.1" andPort:2006]; if (bsdCli.errorCode == NOERRROR) { NSData *data = [NSData dataWithContentsOfFile:@"/Users/hoffmanjon/Documents/GreenGuyLarge.png"]; [bsdCli sendData:data toSocket:bsdCli.sockfd]; } else { NSLog(@"%@",[NSString stringWithFormat:@"Error code %d recieved. ", bsdCli.errorCode]); }
We start off by initializing the BSDSocketClient
object with the IP address 127.0.0.1
and with a port of 2006
. If you are running the sample server on another device, you will need to change the IP address. If there are no issues initializing the client, we load an image and convert it to an NSData
object. You will need to change the location of the file to the location on your machine that contains an image.
We then pass the NSData
object that contains the image to the sendData:toSocket
method.
How it works…
When we created the BSD data server, we went through a three-step process to prepare the TCP server and to create listen on the socket. These were socket (create a socket), bind (bind the socket to the interface), and listen (listen for incoming connections).
When we create the BSD data client, we make the connection in a two-step process. These steps are socket
(create a socket just like the echo server) and connect
(this connects to the server). The client calls the connect()
function to establish a connection with the server. If no error occurs, we have a connection between the server and the client. This connection process is the same code we used to establish a connection with the echo server.
Once we have the connection established with the server, we need to send our data to the server. In our example, we will be sending an image file over; however, this same code can be used to send any binary file. The client and the server just need to agree on what type of file is to be sent.
The first thing we need to do is to convert the file to an NSData
object and pass that to the sendData:toScoket:
method. When the sendData:toSocket:
method has the NSData
object, it converts it to a Uint8
buffer. We then use the send()
function to send the Uint8
buffer to the server.