i am establishing a UDP connection using GCDAsyncSocket(ios device). Everything working fine and im able to send and receive messages, my problem is that i want to exchange data fast. I can send pretty fast data from my iphone to a pc but i cant get at that speed data from pc, more specific i want to be able to get data every 100ms.
I use this function when i connect successfully:
-(void)startRead {
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(startRead) userInfo:nil repeats:YES];
[asyncSocket readDataWithTimeout:-1 tag:0];
}
With this i can read data with 1sec interval but if i try to put 0.1 seconds my program freezes.(Same with values under 1second) Im sure that im doing something wrong here and there will be a way to achieve what i want so if anybody know plz help!!
thanx
I believe the above comment is correct, you've not set the Delegate correctly on init. The socket creation should be something like this
GCDAsyncUdpSocket* udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![udpSocket bindToPort:0 error:&error])
{
[self logError:[NSString stringWithFormat:#"Error binding: %#", error]];
return;
}
if (![udpSocket beginReceiving:&error])
{
[self logError:[NSString stringWithFormat:#"Error receiving: %#", error]];
return;
}
NSString *_host = nil;
uint16_t _port = 0;
[GCDAsyncUdpSocket getHost:&_host port:&_port fromAddress:udpSocket.localAddress];
[self logInfo:[NSString stringWithFormat:#"Socket setup on host %#:%d", _host, _port]];
[self logInfo:#"Socket created successfully."];
Unless you're using a different version of GCDAsyncUdpSocket than I'm familiar with, the correct callback method is actually the below method. This is called automatically when the delegate is set and a packet is received on the correct port.
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext
Related
I'm very new to Objective-C and would like to communicate between an iOS app which I'm working on and my Python 3 socket server (which works). The problem is I don't know how to use sockets in Objective-C and don't know where to start when installing libraries in Xcode 8. For now I just want to be able to send data to the server and receive a response back on the iOS device. I have seen sys.socket.h but again, I don't know how to use it, any help would be much appreciated.
Thanks!
Few years ago I used SocketRocket. I am posting some of the code of it from my old project. I don't know if that still works but you might get the idea of using it.
Connecting to server
NSMutableURLRequest *pushServerRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"ws://192.168.1.1"]];
[pushServerRequest setValue:#"WebSocket" forHTTPHeaderField:#"Upgrade"];
[pushServerRequest setValue:#"Upgrade" forHTTPHeaderField:#"Connection"];
[pushServerRequest setValue:"somekey" forHTTPHeaderField:#"Sec-WebSocket-Protocol"];
SRWebSocket *wsmain = [[SRWebSocket alloc] initWithURLRequest:pushServerRequest]; //Declare this as a global variable in a header file
wsmain.delegate=self;
[wsmain open];
Delegate Methods
-(void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message
{
NSLog(#"Message %#",message);
}
- (void)webSocketDidOpen:(SRWebSocket *)webSocket
{ NSLog(#"Connected");
}
Sending Commands
[wsmain send:commands];
By sending commands, you will receive a response in didReceiveMessage method.
have you seen https://github.com/robbiehanson/CocoaAsyncSocket?
It's easy to use socket
NSString *host = #"10.70.0.22";
int port = 1212;
_socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
NSError *error = nil;
[_socket connectToHost:host onPort:port error:&error];
if (error) {
NSLog(#"%#",error);
}
delegate
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
NSLog(#"success");
}
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
if (err) {
NSLog(#"error %#",err);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self connectToServer];
});
}else{
NSLog(#"disconnect");
}
}
Another option is socket.io. It has server libraries and a iOS client library written in Swift. It's API is quite extensive.
I'm developing an application which is connecting to another device and in order to connect to it my app has to find the IP of it. I'm doing it through UDP socket. I'm sending a message to the server application in the other device and then the server app sends me another message but after I receive it I only use the IP address. Then I want to get it from this .m file to another .m file which is going to make the TCP connection between the two devices. Here's the code I use:
NSString *SearchCommand = #"AT+S";
static int receivedByteCount = 0;
BOOL connectedThroughUDP;
- (void) activate {
connectedThroughUDP = NO;
AsyncUdpSocket *udpSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];
[udpSocket bindToPort:1234 error:nil ];
[udpSocket enableBroadcast:YES error:nil];
NSData* data=[SearchCommand dataUsingEncoding:NSUTF8StringEncoding];
if ([udpSocket sendData:data toHost:#"255.255.255.255" port:30100 withTimeout:3 tag:0])
{
//2 second timeout. onUdpSocket methods will provide results
[udpSocket receiveWithTimeout:2 tag:0];
NSLog(#"Connected.");
}
}
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{
NSString *receiveddata = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
addressOfServer = host;
NSLog(#"addressOfServer = %#", addressOfServer);
connectedThroughUDP = YES;
return YES;
}
- (NSString *) getHost {
return addressOfServer;
}
- (BOOL) isItConnected {
return connectedThroughUDP;
}
addressOfServer is global variable.
In the Log when I want NSLog(#"addressOfServer = %#", addressOfServer); I receive the IP address which I want but then when I want to access it from the getHost method I receive (null).
I know it will be something very simple but it caused me a real headache in the past 3 hours so I would be very thankful if you can help me!
Are you calling these 3 lines right after each other like so:
UDPConnection *udpConnection = [[UDPConnection alloc] init];
[udpConnection activate];
host = [udpConnection getHost];
If so your issue is that [udpConnection activate]; is going to take some time to connect and figure out the address. You are calling [udpConnection getHost]; too soon.
You will need to setup a delegate or completion block that will be triggered when didReceiveData is fired
I am using GCDAsyncUdpSocket to write a UDP socket in my app. The scenario is like this: when users click the button, it will send a broadcast packet in LAN then listen to the response, there is a server in LAN which will respond with one UDP packet. When the app receives the response, it will do something.
I set GCDAsyncUdpSocket as followings:
- (void)setupSocket
{
_udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![_udpSocket bindToPort:18686 error:&error]) {
NSLog(#"Error binding: %#",error);
return;
}
if (![_udpSocket beginReceiving:&error]) {
NSLog(#"Error receiving: %#",error);
return;
}
if (![_udpSocket enableBroadcast:YES error:&error]) {
NSLog(#"Error enableBroadcast: %#",error);
return;
}
}
then i send Packet in button action as following:
NSString *host = #"255.255.255.255";
int port = 8585;
NSString *msg = #"Hello from iOS";
NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
[_udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:0];
in
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext
method i listen the port to do somethings. It works perfectly at beginning, but if you try to click the button later (about 1 hour), then it cannot send UDP packet any more.
My server in LAN will print the data received. I thought there was something wrong with send method. so i use BSD socket methods to send The data. and use GCDAsyncUdpSocket to receive the response. but the same thing happened after a while. this time i can send but cannot receive.
Am i missing something about GCDAsyncUdpSocket? why it cannot send/receive after a while? Any help would be much appreciated.
It may be some timeout setting. Implement the GCDAsyncUdpSocketDelegate protocol to fetch detailed information about what is going on.
The hard solution is to establish a new connection.
I have implemented gcdasynsocket in my app and performing multiple write operations. The delegate didWriteDataWithTag is called twice but didreaddata is called only once (ie) for only one write operation.
-(void)connectToHost:(NSString*)ip andPort:(NSString*)port
{
if(![asyncSocket isConnected])
{
dispatch_queue_t mainQueue = dispatch_get_main_queue();
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
NSError *error = nil;
uint16_t portNumber = (uint16_t)[port integerValue];
if (![asyncSocket connectToHost:ip onPort:portNumber withTimeout:-1 error:&error])
{
NSLog(#"Error connecting: %#", error);
}
else
{
NSLog(#"Connecting...");
}
}}
GCDasyncsocket delegate methods
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
NSLog(#"connected to host");
[asyncSocket writeData:dataToBeWritten1 withTimeout:-1 tag:1000];
[asyncSocket writeData:dataToBeWritten2 withTimeout:-1 tag:2000];
}
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
[asyncSocket readDataWithTimeout:-1 tag:tag];
}
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
if (tag==1000)
{
NSLog(#"didReadData and tag-----%#-----%ld",data,tag);
[asyncSocket readDataWithTimeout:-1 tag:2000];
}
else if(tag==2000)
{
NSLog(#"didReadData and tag-----%#-----%ld",data,tag);
[asyncSocket readDataWithTimeout:-1 tag:1000];
}
}
I am not sure what is going wrong. Please help me to fix the issue
I think you're getting tripped up by the inner workings of the TCP protocol. TCP is a stream-based protocol, not a message-based protocol. In other words, it guarantees that bytes will arrive in the exact same order they were sent, but there are no guarantees about how those bytes will be grouped into packets or read operations.
Specifically, I suspect your two writes are being aggregated, either in the transmitter or receiver, into a single read. In other words, this behavior is entirely normal and expected.
You'll need to separate your data into logical units using some other way besides relying on every write causing exactly one read in the receiver. One common technique is to start every message with a length field that allows the receiver to not only read each message but also to know how long it is and to be able to find where the next message starts.
Here's a good explanation on how to go about doing that: Proper technique for sending multiple pieces of data of arbitrary length over TCP socket
My game needs to fill tableView cells with a bunch of things from my server database. This has been working fine. Then I upgraded Xcode to 4.6 and targeted iOS6.1, to please the App Review Team folks. Now, one of my connections never completes. (All of the other Posts seem to work correctly, as always.) Here's my post:
- (void) fillCells {
Cell_QtoA *newCell = [[Cell_QtoA alloc] initCellUser:usrID Grp:grpID Qtn:0 Gnm:#"na" Cat:#"na" Sit:#"na" Pfl:#"na" Lks:0 isA:0 ddA:0 ];
NSMutableURLRequest *reqPost = [SimplePost urlencodedRequestWithURL:[NSURL URLWithString:kFillCells] andDataDictionary:[newCell toDictC]];
(void) [[NSURLConnection alloc] initWithRequest:reqPost delegate:self];
}
I think it's working fine. The PHP and database haven't changed. Everything worked great yesterday, before the upgrades. Here's my connection method:
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"data = %#", data);
NSString *error;
NSArray *array = (NSArray *)[NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:0 errorDescription:&error];
if( error ) {
NSLog(#"Error = %#", error);
return;
}
NSLog(#"1st object in array of %d is %#", [array count], array );
}
Because I suspected net speeds to be an issue, I added a timer to the call, which I never needed before:
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(fillCells) userInfo:nil repeats:YES];
The timer didn't help. Still get errors:
"Unexpected EOF" and "Unexpected character z (or whatever) at Line 1"
The NSLog of data shows hex data that appears cut off, like:
<3c3f786d 6c207665 ... 63743e0a 3c2f6172 7261793e 0a3c2f70 6c697374 3e>
It's like the reception is being interrupted. Anyone know what's happening here? Thanks!
You aren't using all the response data; as mention in the NSURLConnectionDelegate reference:
The newly available data. The delegate should concatenate the contents
of each data object delivered to build up the complete data for a URL
load.
So you need to create an NSData instance variable; clear before the request and append to it whenever new data arrives. Then use the didFinishLoading delegate method to trigger the call to propertyListFromData with the complete response.