How can i send image over socket in iPhone. I tried with string the code i used is as follows, now i need to send image over socket.
CFWriteStreamRef writeStream = NULL;
CFStringRef host = CFSTR("192.168.1.211");
UInt32 port = 8001;
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, NULL, &writeStream);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
if(!CFWriteStreamOpen(writeStream)) {
NSLog(#"Error Opening Socket");
}
else{
UInt8 buf[] = "Abc";
int bytesWritten = CFWriteStreamWrite(writeStream, buf, strlen((char*)buf));
NSLog(#"Written: %d", bytesWritten);
if (bytesWritten < 0) {
CFStreamError error = CFWriteStreamGetError(writeStream);
}
}
Regards,
The image has to be converted to base64 string and transferred through socket.
Here is the code snippet for base-64 conversion in Objective c
- (NSString *)encodeToBase64String:(UIImage *)image {
return [UIImagePNGRepresentation(image) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
}
Swift
let strBase64:String = imageData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
Here is the reference
Related
When I get a NetService object,I try to do:
NSNetService *ss=[netArray objectAtIndex:indexPath.row];
ss.delegate=self;
[ss resolveWithTimeout:3.0];
On the delegate method:
-(void)netServiceDidResolveAddress:(NSNetService *)sender
{
NSArray *address=sender.addresses;
NSData *addressData=[NSData dataWithBytes:address length:sizeof(address)];
/*
How?
*/
}
Thanks.
// Sent when addresses are resolved
- (void)netServiceDidResolveAddress:(NSNetService *)netService
{
// Make sure [netService addresses] contains the
// necessary connection information
if ([self addressesComplete:[netService addresses]
forServiceType:[netService type]]) {
[services addObject:netService];
}
}
// Verifies [netService addresses]
- (BOOL)addressesComplete:(NSArray *)addresses
forServiceType:(NSString *)serviceType
{
// Perform appropriate logic to ensure that [netService addresses]
// contains the appropriate information to connect to the service
NSData *myData = nil;
myData = [addresses objectAtIndex:0];
NSString *addressString;
int port=0;
struct sockaddr *addressGeneric;
struct sockaddr_in addressClient;
addressGeneric = (struct sockaddr *) [myData bytes];
switch( addressGeneric->sa_family ) {
case AF_INET: {
struct sockaddr_in *ip4;
char dest[INET_ADDRSTRLEN];
ip4 = (struct sockaddr_in *) [myData bytes];
port = ntohs(ip4->sin_port);
addressString = [NSString stringWithFormat: #"IP4: %s Port: %d", inet_ntop(AF_INET, &ip4->sin_addr, dest, sizeof dest),port];
}
break;
case AF_INET6: {
struct sockaddr_in6 *ip6;
char dest[INET6_ADDRSTRLEN];
ip6 = (struct sockaddr_in6 *) [myData bytes];
port = ntohs(ip6->sin6_port);
addressString = [NSString stringWithFormat: #"IP6: %s Port: %d", inet_ntop(AF_INET6, &ip6->sin6_addr, dest, sizeof dest),port];
}
break;
default:
addressString=#"Unknown family";
break;
}
NSLog(#"Client Address: %#",addressString);
return YES;
}
This is the output
Client Address: IP4: 192.168.69.38 Port: 58612
I found a post which suggests the following solution.
NSString* addressString = [[NSString alloc] initWithData:addressData encoding:NSASCIIStringEncoding];
Though it does not output a human readable string for me... It might work for you.
This is what is written to the console when I print the NSData object.
<10026a5e 0a0a7893 00000000 00000000>
Meanwhile, I found out that the second segment is the hexadecimal form of the ip-address. In this example it is ...
10.10.120.147 // 0a0a7893
I have written a Host class that does the conversion. The NSString extension can be found here. I only use the first 16-bytes address and ignore all others. Feel free to extend the class.
We have following code for connecting to our server. This is part of iPhone App.
Problem is that recv(CFSocketGetNative(inSocketRef), &length, sizeof(length), 0);
call returns 0 after exactly 60 sec. We are not sending anything from server. I want it to wait for data or disconnection (either server or client initiated). However, it always returns after 60 sec.
What am I doing wrong here?
void CallbackHandlerConnectionHandler(CFSocketRef inSocketRef, CFSocketCallBackType inType,
CFDataRef inAddress, const void *inData, void *inInfo)
{
ChatServerConnectionHandler *conHandler = (ChatServerConnectionHandler *)inInfo;
if([conHandler respondsToSelector:#selector(dataRecievedFromServer:)])
{
int res = 0;
SInt32 length;
res = recv(CFSocketGetNative(inSocketRef), &length, sizeof(length), MSG_PEEK);
if(0 >= res || (length < 0))
{
//Disconnect the connection, as some has occcured in the sockets..
[conHandler performSelector:#selector(errorEncountered)];
NSLog(#"Error occured in server!!");
return;
}
printf ("good data")
}
}
-(BOOL) connectToServer:(NSString *)ipAddress Port:(int)portNumber
{
connectionState = eConnectionEstablishInProgress;
self.threadStopped = NO;
CFRunLoopSourceRef source;
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *host;
host = gethostbyname([ipAddress cStringUsingEncoding:NSUTF8StringEncoding]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct timeval timeout;
if (sockfd < 0)
{
error("ERROR opening socket");
connectionState = eNoConnection;
return NO;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portNumber);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
/* Creates a CFSocket object for a pre-existing native socket */
CFSocketContext socketContext={0,self,NULL,NULL,NULL};
socketRef = CFSocketCreateWithNative(kCFAllocatorDefault,
sockfd,
kCFSocketReadCallBack,
CallbackHandlerConnectionHandler,
&socketContext);
source = CFSocketCreateRunLoopSource(NULL, socketRef, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
CFRelease(source);
source = nil;
InstallSignalHandlers();
CFDataRef socketAddress;
socketAddress = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8 *)&serv_addr, sizeof(serv_addr), kCFAllocatorNull);
CFSocketError result=CFSocketConnectToAddress(socketRef, socketAddress, 0);
CFRelease(socketAddress);
if(kCFSocketSuccess == result)
{
//printf("Socket connection established");
self.serverRunning = YES;
connectionState = eConnectionEstablised;
NSLog(#"\nCall Connection accepted callback.");
if([delegate respondsToSelector:#selector(conectionEstablishedWithTheServer)])
{
[delegate performSelector:#selector(conectionEstablishedWithTheServer)];
}
}
else
{
//printf("Unable to create socket why???***");
connectionState = eNoConnection;
if(socketRef)
CFRelease(socketRef);
socketRef = nil;
return NO;
}
while(FALSE == self.threadStopped)
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, FALSE);
}
NSLog(#"\nOut of Server socket connection thread.");
self.serverRunning = NO;
if([delegate respondsToSelector:#selector(conectionFinishedWithServer)])
{
[delegate performSelector:#selector(conectionFinishedWithServer)];
}
if(socketRef)
{
if(CFSocketIsValid(socketRef))
CFSocketInvalidate(socketRef);
}
return YES;
}
This looks like a server problem - or rather functionality: closing inactive connections to keep enough free resources.
If you didn't write the server code try to contact the author.
The packet you mention [FIN, ACK] is a packet that closes your socket: you should check the IP adresses but the server is most probably the initiator of this packet.
how can i clear an CFStream buffer?
Everytime i read from socket there is still data from an old request, i mean complete response to an old request not just a fragment of it.
Am i missing something ?
This is a function i use to initialize the connection:
-(void)openSocketConnection:(UInt32)port: (NSString *)host
{
NSString *hoststring = [[NSString alloc] initWithString:host];
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,(__bridge CFStringRef)hoststring ,
port,&_nnet_readStream,&_nnet_writeStream);
CFWriteStreamCanAcceptBytes(_nnet_writeStream);
CFWriteStreamSetProperty(_nnet_writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFReadStreamSetProperty(_nnet_readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
if(!CFWriteStreamOpen(_nnet_writeStream)) {
NSLog(#"Error Opening Write Socket");
}
if(!CFReadStreamOpen(_nnet_readStream)) {
NSLog(#"Error Opening Write Socket");
}
}
This is a function i use to read data from socket:
BOOL done = NO;
NSMutableString* result = [NSMutableString string];
while (!done)
{
if (CFReadStreamHasBytesAvailable(_nnet_readStream))
{
UInt8 buf[1024];
CFIndex bytesRead = CFReadStreamRead(_nnet_readStream, buf, 1024);
if (bytesRead < 0)
{
CFStreamError error = CFReadStreamGetError(_nnet_readStream);
NSLog(#"%#",error);
} else if (bytesRead == 0)
{
if (CFReadStreamGetStatus(_nnet_readStream) == kCFStreamStatusAtEnd)
{
done = YES;
}
} else
{
[result appendString:[[NSString alloc] initWithBytes:buf length:bytesRead encoding:NSUTF8StringEncoding]];
}
} else
{
done = YES;
}
}
You seem to assume that when you get data from the host on the other end it will always be available all in one go.
I don't know what the underlying protocol is, but in general it's entirely possible that the remote end will try and send 1600 bytes and that you'll get 1500 bytes but then have to wait a few milliseconds (or even seconds) for the next 100 bytes. Meanwhile CFReadStreamHasBytesAvailable would return false and so your code would set your done flag even though you haven't read all the data the server sent.
I have a problem with my socket program.
I create the client program (my code is below)
I have a problem when i close the socket with the disconnect method.
CFSocketRef s;
-(void)CreaConnessione
{
CFSocketError errore;
struct sockaddr_in sin;
CFDataRef address;
CFRunLoopSourceRef source;
CFSocketContext context = { 0, self, NULL, NULL, NULL };
s = CFSocketCreate(
NULL,
PF_INET,
SOCK_STREAM,
IPPROTO_TCP,
kCFSocketDataCallBack,
AcceptDataCallback,
&context);
memset(&sin, 0, sizeof(sin));
int port = [fieldPorta.text intValue];
NSString *tempIp = fieldIndirizzo.text;
const char *ip = [tempIp UTF8String];
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = (long)inet_addr(ip);
address = CFDataCreate(NULL, (UInt8 *)&sin, sizeof(sin));
errore = CFSocketConnectToAddress(s, address, 0);
if(errore == 0){
buttonInvioMess.enabled = TRUE;
fieldMessaggioInvio.enabled = TRUE;
labelTemp.text = [NSString stringWithFormat:#"Connesso al Server"];
CFRelease(address);
source = CFSocketCreateRunLoopSource(NULL, s, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(),
source,
kCFRunLoopDefaultMode);
CFRelease(source);
CFRunLoopRun();
}
else{
labelTemp.text = [NSString stringWithFormat:#"Errore di connessione. Verificare Ip e Porta"];
switchConnection.on = FALSE;
}
}
//the socket doesn't disconnect
-(void)Disconnetti{
CFSocketInvalidate(s);
CFRelease(s);
}
-(IBAction)Connetti
{
if(switchConnection.on)
[self CreaConnessione];
else
[self Disconnetti];
}
If you're trying to reuse the socket which you have invalidated. I guess you cant use the same socket object again.
because once i remove invalidating socket from my code. the code works pretty good on every single time i try to make connection after disconnecting..
Essentially I'm sending data to a Java Socket Server from an iPhone app however something rather strange happens, it doesn't receive the data until the iPhone application is closed! I'm sure there is something I'm missing but I just can't seem to find it, it's all quite odd.
Here is how my connection is created:
-(CFSocketRef)initSocket {
CFSocketContext context = {
.version = 0,
.info = self,
.retain = NULL,
.release = NULL,
.copyDescription = NULL
};
sockety = CFSocketCreate(
kCFAllocatorDefault,
PF_INET,
SOCK_STREAM,
IPPROTO_TCP,
kCFSocketDataCallBack^kCFSocketConnectCallBack,
socketCallBack,
&context
);
uint16_t port = 4444;
struct sockaddr_in addr4;
memset(&addr4, 0, sizeof(addr4));
addr4.sin_family = AF_INET;
addr4.sin_len = sizeof(addr4);
addr4.sin_port = htons(port);
const char *ipaddress = "192.168.1.5";
inet_aton(ipaddress, &addr4.sin_addr);
NSData *address = [NSData dataWithBytes:&addr4 length:sizeof(addr4)];
CFSocketError error = CFSocketConnectToAddress(sockety, (CFDataRef)address, 1);
if(error != kCFSocketSuccess )
{
Faliure = YES;
}
else{
ViewNo = 2;
}
CFRunLoopSourceRef source;
source = CFSocketCreateRunLoopSource(NULL, sockety, 1);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
CFRelease(source);
return sockety;
}
Heres how the message is sent:
const char *sendStrUTF = [sentmessage UTF8String];
NSData *dataOut = [NSData dataWithBytes: sendStrUTF length: strlen(sendStrUTF)];
CFSocketSendData(sockety, NULL, (CFDataRef) dataOut, 0);
Any help would be greatly appreciated!
Thanks in advance,
Ozzie
Is your call to CFSocketSendData being done on a (blocked) GUI thread?
I would experiment with wrapping those 3 lines in a performSelectorInBackground / or after delay combinations.
NSData *dat=[stringToSend dataUsingEncoding:NSASCIIStringEncoding];
CFSocketError w =CFSocketSendData(_socket, NULL,(CFDataRef)dat, 0);
if (w==kCFSocketSuccess) {
NSLog(#"success");
}