This is my Client and Server code for CFSocket communication but on successful connection this code crashes.
Client.m
-(void)createConnection
{
CFSocketContext socketContext = {0,(__bridge void *)(self),NULL,NULL,NULL};
_socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketConnectCallBack,(CFSocketCallBack)kCFSocketConnectCallBack, &socketContext);
if (_socket != nil) {
struct sockaddr_in addr4;
memset (& addr4, 0, sizeof (addr4));
addr4.sin_len = sizeof (addr4);
addr4.sin_family = AF_INET;
addr4.sin_port = htons (8888);
NSString *strAddress = #"xxx.xxx.x.xxx";
addr4.sin_addr.s_addr = inet_addr ([strAddress UTF8String]);
CFDataRef address = CFDataCreate (kCFAllocatorDefault, (UInt8 *) & addr4, sizeof (addr4));
CFSocketConnectToAddress (_socket,address,-1);
CFSocketEnableCallBacks(_socket, kCFSocketConnectCallBack);
CFRunLoopRef cRunRef = CFRunLoopGetCurrent ();
CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource (kCFAllocatorDefault, _socket, 0);
CFRunLoopAddSource (cRunRef,sourceRef,kCFRunLoopCommonModes);
char ethadd []= "helloworld";
CFDataRef Data = CFDataCreate(NULL, (const UInt8*)ethadd, sizeof(ethadd));
int socket_error = CFSocketSendData (_socket, (CFDataRef) address, (CFDataRef) Data, 10);
if (socket_error < 0){
NSLog(#"Data could not be sent!");
// return EXIT_FAILURE;
}
else NSLog(#"Data Sent");
CFRelease (sourceRef);
}
}
void TCPServerConnectCallBack (CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void * data, void * info) {
if (data != NULL) {
// When the socket is kCFSocketConnectCallBack failure callback failed to return an error code pointer, other returns NULL
NSLog (#"connection failed");
return;
}
Client * client = (__bridge Client *) info;
[client readStream];
}
- (void)readStream {
char buffer [1024];
while (recv (CFSocketGetNative (_socket), // ??Socket associated with the authority has failed to return -1: INVALID_SOCKET is
buffer, sizeof (buffer), 0)) {
NSLog (#"%#", [NSString stringWithUTF8String: buffer]);
}
}
- (void) SendMessage :(NSString *)text {
// [self createConnection];
NSString * stringTosend = text;
char * data = (char *)[stringTosend UTF8String];
send (CFSocketGetNative (_socket), data, strlen (data) + 1, 0);
}
Server.m
-(void)setupSocket
{
setupSocket();
}
int setupSocket () {
_socket = CFSocketCreate (kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)kCFSocketAcceptCallBack, NULL);
if (NULL == _socket) {
NSLog (# "Cannot create socket!");
return 0;
}
int optval = 1;
setsockopt (CFSocketGetNative (_socket), SOL_SOCKET, SO_REUSEADDR, // ??allow reuse of local address and port
(void *) & optval, sizeof (optval));
struct sockaddr_in addr4;
memset (& addr4, 0, sizeof (addr4));
addr4.sin_len = sizeof (addr4);
addr4.sin_family = AF_INET;
addr4.sin_port = htons (8888);
addr4.sin_addr.s_addr = inet_addr ([#"xxx.xxx.x.xxx" UTF8String]);//htlon(INADDR_ANY)
CFDataRef address = CFDataCreate (kCFAllocatorDefault, (UInt8 *) & addr4, sizeof (addr4));
if (kCFSocketSuccess != CFSocketSetAddress (_socket, address)) {
NSLog (# "Bind to address failed!");
if (_socket)
CFRelease (_socket);
_socket = NULL;
return 0;
}
CFSocketEnableCallBacks(_socket, kCFSocketAcceptCallBack);
CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent ();
CFRunLoopSourceRef source = CFSocketCreateRunLoopSource (kCFAllocatorDefault, _socket, 0);
CFRunLoopAddSource (cfRunLoop, source, kCFRunLoopCommonModes);
return 1;
}
void TCPServerAcceptCallBack (CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void * data, void * info) {
if (kCFSocketAcceptCallBack == type) {
// Local socket handle
CFSocketNativeHandle nativeSocketHandle = * (CFSocketNativeHandle *) data;
uint8_t name [SOCK_MAXADDRLEN];
socklen_t nameLen = sizeof (name);
if (0 != getpeername (nativeSocketHandle, (struct sockaddr *) name, & nameLen)) {
NSLog (#"error");
// Exit (1);
}
NSLog (# "%s connected.", inet_ntoa (((struct sockaddr_in *) name) -> sin_addr));
CFReadStreamRef iStream;
CFWriteStreamRef oStream;
CFReadStreamClientCallBack readStream;
CFReadStreamClientCallBack writeStream;
CFWriteStreamRef wStream;
// Create a socket connection can read and write
CFStreamCreatePairWithSocket (kCFAllocatorDefault, nativeSocketHandle, &iStream, & oStream);
if (iStream && oStream) {
CFStreamClientContext streamContext = {0, NULL, NULL, NULL};
if (! CFReadStreamSetClient (iStream, kCFStreamEventHasBytesAvailable,
readStream, // callback function is called when the data readable
&streamContext)) {
// Exit (1);
}
if (! CFReadStreamSetClient (iStream, kCFStreamEventCanAcceptBytes, writeStream, &streamContext)) {
// Exit (1);
}
CFReadStreamScheduleWithRunLoop (iStream, CFRunLoopGetCurrent (), kCFRunLoopCommonModes);
CFWriteStreamScheduleWithRunLoop (wStream, CFRunLoopGetCurrent (), kCFRunLoopCommonModes);
CFReadStreamOpen (iStream);
CFWriteStreamOpen (wStream);
}
else
{
close (nativeSocketHandle);
}
}
}
// Read data
void readStream (CFReadStreamRef stream, CFStreamEventType eventType, void * clientCallBackInfo) {
UInt8 buff [255];
CFReadStreamRead (stream, buff, 255);
printf ("received:%s", buff);
}
void writeStream (CFWriteStreamRef stream, CFStreamEventType eventType, void * clientCallBackInfo) {
outputStream = stream;
}
//int main()
//{
// char * str = "nihao";
// UInt8 buff [255];
// if (outputStream != NULL) {
// CFWriteStreamWrite (outputStream, buff, strlen (str) + 1);
// }
// else
// {
// NSLog (# "Cannot send data!");
// }
//}
// Open up a thread in the thread function
void runLoopInThread () {
int res = setupSocket ();
if (res) {
EXIT_FAILURE;
}
CFRunLoopRun (); // run the current thread CFRunLoop of objects
}
In the above code crashes for Server when CFSocketConnectToAddress executes in Client and after that client app also crashes.
Dealing with a CFSockets will get you in the world of dealing with POSIX foundations and stuff. If your looking for a simple echo/chat server, you should firstly go to NSStream. It's way easier. Here's an example:
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)HOST, PORT, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (NSOutputStream *)CFBridgingRelease(writeStream);
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
And handling the input be like:
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
uint8_t buffer[100240];
NSInteger len;
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
if (nil != output) {
NSLog(#"Server Response: %#", output);
[self stream:theStream didRecieveResponse:output];
}
}
}
}
break;
case NSStreamEventErrorOccurred:
[self requestDidFailWithResults:#"Can not connect to the host!" andError:theStream.streamError];
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
theStream = nil;
break;
case NSStreamEventEndEncountered:
[self requestDidFailWithResults:#"Request ended" andError:theStream.streamError];
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
theStream = nil;
break;
case NSStreamEventHasSpaceAvailable:
NSLog(#"OutStream is ready");
break;
default:
[self requestDidFailWithResults:#"Unknown event" andError:theStream.streamError];
}
}
_socket = CFSocketCreate (kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)kCFSocketAcceptCallBack, NULL);
In above method i had to pass my callback method instead of "(CFSocketCallBack)kCFSocketAcceptCallBack".Which fixed my issue.
How to write UIImage and send data to receive server. I have try but the NSOutputStream only can write maximum 136768 bytes in stream and I only save a fraction of image. Very thankful for help. Here is my code:
From UIImage picker
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = info[UIImagePickerControllerOriginalImage];
NSData *imgData = UIImageJPEGRepresentation(image,1.0f);
NSLog(#"%d",imgData.length);
NSMutableData *completeData = [[NSMutableData alloc]init];
[completeData appendData:imgData];
NSInteger bytesWritten = 0;
while ( completeData.length > bytesWritten )
{
//sending NSData over to server
NSInteger writeResult = [outputStream write:[completeData bytes]+bytesWritten maxLength:[completeData length]-bytesWritten];
if ( writeResult == -1 )
NSLog(#"error code here");
else
bytesWritten += writeResult;
if (bytesWritten == writeResult) {
[self dismissViewControllerAnimated:YES completion:nil];
}
}
}
Stream delegate
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
// An NSStream delegate callback that's called when events happen on our
// network stream.
{
#pragma unused(aStream)
assert(aStream == self.networkStream);
switch (eventCode) {
case NSStreamEventOpenCompleted: {
[self _updateStatus:#"Opened connection"];
} break;
case NSStreamEventHasBytesAvailable: {
if (aStream == self.networkStream) {
uint8_t buffer[5000];
int len;
while ([self.networkStream hasBytesAvailable]) {
len = [self.networkStream read:buffer maxLength:sizeof(buffer)];
NSLog(#"len=%d", len);
if (len > 0) {
NSData *pictureData = [NSData dataWithBytes:buffer length:len];
[sharedManager.pictureMutableData appendData:pictureData];
NSLog(#"%d",sharedManager.pictureMutableData.length);
}
}
}
case NSStreamEventHasSpaceAvailable: {
[self _didReceiveDataImage:sharedManager.pictureMutableData];
NSLog(#"%d",sharedManager.pictureMutableData.length);
} break;
case NSStreamEventErrorOccurred: {
[self _stopReceiveWithStatus:#"Stream open error"];
} break;
case NSStreamEventEndEncountered: {
// ignore
} break;
default: {
assert(NO);
} break;
}
}
Your code is strange:
You implement the events for an input stream (NSStreamEventHasBytesAvailable).
The data is not written in one part, but you have to send it part by part. The size of the part is determined by the OS. If the data is larger, you have to write the next part in the delegate method for the event NSStreamEventHasSpaceAvailable. But you do not write there. Instead you set received data!?
Have a look here:
https://developer.apple.com/library/IOs/documentation/Cocoa/Conceptual/Streams/Articles/WritingOutputStreams.html#//apple_ref/doc/uid/20002274-1002233
I am new to socket programming.I am trying to track bytes sent and received through all sockets opened in my iPhone. Which data structure present in iOS, gives information about these? I tried below code posted in one of the SO question, but it is giving data from last reboot time. I want to list all sockets established in my iPhone and track bytes sent and received through each socket
- (NSArray *)getDataCounters {
BOOL success;
struct ifaddrs *addrs;
const struct ifaddrs *cursor;
const struct if_data *networkStatisc;
int WiFiSent = 0;
int WiFiReceived = 0;
int WWANSent = 0;
int WWANReceived = 0;
NSString *name=[[[NSString alloc]init]autorelease];
success = getifaddrs(&addrs) == 0;
if (success)
{
cursor = addrs;
while (cursor != NULL)
{
name=[NSString stringWithFormat:#"%s",cursor->ifa_name];
NSLog(#"ifa_name %s == %#\n", cursor->ifa_name,name);
// names of interfaces: en0 is WiFi ,pdp_ip0 is WWAN
if (cursor->ifa_addr->sa_family == AF_LINK)
{
if ([name hasPrefix:#"en"])
{
networkStatisc = (const struct if_data *) cursor->ifa_data;
WiFiSent+=networkStatisc->ifi_obytes;
WiFiReceived+=networkStatisc->ifi_ibytes;
NSLog(#"WiFiSent %d ==%d",WiFiSent,networkStatisc->ifi_obytes);
NSLog(#"WiFiReceived %d ==%d",WiFiReceived,networkStatisc->ifi_ibytes);
}
if ([name hasPrefix:#"pdp_ip"])
{
networkStatisc = (const struct if_data *) cursor->ifa_data;
WWANSent+=networkStatisc->ifi_obytes;
WWANReceived+=networkStatisc->ifi_ibytes;
NSLog(#"WWANSent %d ==%d",WWANSent,networkStatisc->ifi_obytes);
NSLog(#"WWANReceived %d ==%d",WWANReceived,networkStatisc->ifi_ibytes);
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
return [NSArray arrayWithObjects:[NSNumber numberWithInt:WiFiSent], [NSNumber numberWithInt:WiFiReceived],[NSNumber numberWithInt:WWANSent],[NSNumber numberWithInt:WWANReceived], nil];
I think you should go from basics.
This is how we open socket for input and outputsream.
- (IBAction)searchForSite:(id)sender
{
NSString *urlStr = [sender stringValue];
if (![urlStr isEqualToString:#""]) {
NSURL *website = [NSURL URLWithString:urlStr];
if (!website) {
NSLog(#"%# is not a valid URL");
return;
}
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 80, &readStream, &writeStream);
NSInputStream *inputStream = (__bridge_transfer NSInputStream *)readStream;
NSOutputStream *outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
/* Store a reference to the input and output streams so that
they don't go away.... */
...
}
}
this is the delegate method,whick will called every time when you will read or write to socket.
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
break;
case NSStreamEventHasSpaceAvailable
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
break;
default:
NSLog(#"Unknown event");
}
}
for more information refer links.
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Streams/Articles/NetworkStreams.html#//apple_ref/doc/uid/20002277-BCIDFCDI
http://www.raywenderlich.com/3932/networking-tutorial-for-ios-how-to-create-a-socket-based-iphone-app-and-server
Im writing an IOS application for my first time. It is supposed to connect to a static IP device, and send certain "known" commands to it. But for some reason Im unable to establish a connection.
Bellow are the functions I use to establish my connection, and write data to the port.
-(void)connection//:(NSString *)serviceName forIpAddress:(NSString *)ipAddress forPort:(NSString *)portNo
{
if(input && output)
[self close];
NSString *urlString = [NSString stringWithFormat:#"%.%.%.%", "192.168.3.120"];
NSURL *website = [NSURL URLWithString:urlString];
if (!website) {
NSLog(#"%# is not a valid URL", website);
}
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)[website host], 43, &readStream, &writeStream);
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
NSInputStream *input = (__bridge NSInputStream *)readStream;
NSOutputStream *output= (__bridge NSOutputStream *)writeStream;
}
- (void)open {
[input setDelegate:self];
[output setDelegate:self];
[input scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[output scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode]; [input open];
[output open];
}
-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
NSString *event;
switch (streamEvent)
{
case NSStreamEventNone:
event = #"NSStreamEventNone";
break;
case NSStreamEventOpenCompleted:
event = #"NSStreamEventOpenCompleted";
break;
case NSStreamEventHasBytesAvailable:
event = #"NSStreamEventHasBytesAvailable";
if (theStream == input)
{
uint8_t buffer[1024];
NSInteger len;
while ([input hasBytesAvailable])
{
len = [input read:buffer maxLength:1024];
if (len > 0)
{
NSMutableString *output = [[NSMutableString alloc]initWithBytes:buffer length:len encoding:NSUTF8StringEncoding]; NSLog(#"Received data--------------------%#", output);
}
}
}
break;
case NSStreamEventHasSpaceAvailable:
event = #"NSStreamEventHasSpaceAvailable";
break;
case NSStreamEventErrorOccurred:
event = #"NSStreamEventErrorOccurred";
//[self close];
break;
case NSStreamEventEndEncountered:
break; default:
event = #"NSStreamEventEndEncountered";
//[self close];
event = #"Unknown"; break;
}
NSLog(#"event------%#",event);
}
- (void)close
{
[input close];
[output close];
[input removeFromRunLoop:[NSRunLoop currentRunLoop]forMode:NSDefaultRunLoopMode];
[output removeFromRunLoop:[NSRunLoop currentRunLoop]forMode:NSDefaultRunLoopMode];
[input setDelegate:nil];
[output setDelegate:nil];
input = nil;
output = nil;
}
- (void)dataSending:(NSString*)data
{
if(output)
{
if(![output hasSpaceAvailable])
return;
NSData *_data=[data dataUsingEncoding:NSUTF8StringEncoding];
NSInteger data_len = [_data length];
uint8_t *readBytes = (uint8_t *)[_data bytes];
int byteIndex=0;
unsigned int len=0;
while (TRUE)
{
len = ((data_len - byteIndex >= 40960) ? 40960 : (data_len-byteIndex));
if(len==0)
break;
uint8_t buf[len];
(void)memcpy(buf, readBytes, len);
len = [output write:(const uint8_t *)buf maxLength:len];
byteIndex += len;
readBytes += len;
}
NSLog(#"Sent data----------------------%#",data);
}
}
I do call the mentioned functions through that code as a test, and nothing happens
- (IBAction)pumpchange:(id)sender {
[self connection];
[self open];
if ([self.pump backgroundImageForState:(UIControlStateNormal)]==[UIImage imageNamed:#"PumpOff.png"])
{
[self.pump setBackgroundImage:[UIImage imageNamed:#"PumpOn.png"] forState:(UIControlStateNormal)];
[self dataSending:#"pump_on"];
}
else //if ([self.pump backgroundImageForState:(UIControlStateNormal)]==[UIImage imageNamed:#"PumpOn.png"])
{
[self.pump setBackgroundImage:[UIImage imageNamed:#"PumpOff.png"] forState:(UIControlStateNormal)];
[self dataSending:#"pump_off"];
}
[self close];
}
Thanks in Advance
There seem to be some misunderstandings how format strings work, because
NSString *urlString = [NSString stringWithFormat:#"%.%.%.%", "192.168.3.120"];
just gives you the string #"...". Perhaps you meant
NSString *urlString = [NSString stringWithFormat:#"%d.%d.%d.%d", 192, 168, 3, 120];
or
NSString *urlString = [NSString stringWithFormat:#"%s", "192.168.3.120"];
But you don't need a format string at all:
NSString *urlString = #"192.168.3.120";
I am learning iOS network programming from this tutorial. I tried modifying the code so that a response is sent to the server immediately after a connection is successful. The only part of the code I change is in this function. The problem is that the app stalls and nothing happens on the line [outputStream write:[data bytes] maxLength:[data length]]; Thus NSLog(#"sent test"); does not get executed. What am I doing wrong?
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSLog(#"stream event %i", streamEvent);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
//my code
if (theStream == outputStream) {
NSLog(#"outputStream");
NSData* data = [NSData dataWithBytes:#"test" length:4];
[outputStream write:[data bytes] maxLength:[data length]];
NSLog(#"sent test");
} //end my code
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
uint8_t buffer[1024];
int len;
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
//...
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[theStream release];
theStream = nil;
break;
default:
NSLog(#"Unknown event");
}
}
EDIT: solution found here
How to use NSOutputStream's write message?
ok while i was working with raw socket connections i have used that code to send data to server. it might be helpful to you
if (theStream == outputStream) {
NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];//str is my string to send
int byteIndex = 0;
uint8_t *readBytes = (uint8_t *)[data bytes];
readBytes += byteIndex; // instance variable to move pointer
int data_len = [data length];
// NSLog(#"%i",[data length]);
unsigned int len = ((data_len - byteIndex >= 1024) ?
1024 : (data_len-byteIndex));
uint8_t buf[len];
(void)memcpy(buf, readBytes, len);
len = [outputStream write:(const uint8_t *)buf maxLength:len];
byteIndex += len;
}