I am new to objective C, as a whole and iOS in particular, but i spent the last day to learn it.
i've been trying to create a simple app that reads data from a socket.
I understood that Asyncsocket is the best solution and have started working with it, but I encountered a problem.. it goes through all the delegates (connected to host, read data, disconnected) but then it drifts off and gets stuck somewhere.
heres the code:
- (void) connect:(NSString *)ip PORT:(NSInteger)port
{
//open asyncsoket
connectSocket = [[AsyncSocket alloc] initWithDelegate:self];
[connectSocket setDelegate:self];
// open connection
NSError *error = nil;
if (![connectSocket connectToHost:ip onPort:port error:&error]) {
NSLog(#"Error starting client: %#", error);
return;
}
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{
// if connection was succeful read from socket
NSLog(#"connected to server");
[sock readDataWithTimeout:-1.0 tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
//if did read data
[connectSocket readDataWithTimeout:-1 tag:0];
to_pass = data;
[sock disconnect];
}
- (void)onSocketDidDisconnect:(AsyncSocket *)sock{
// nothing to do
}
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{
//nothing to do
}
if i follow by break points it seems i goes through all those it needs, but then goes to assembly code and stops here:
libsystem_kernel.dylib`mach_msg_trap:
0x2178f70: movl $4294967265, %eax
0x2178f75: calll 0x217f4bc ; _sysenter_trap
0x2178f7a: ret ----> right here
0x2178f7b: nop
Related
I'm trying to send a message to a server and receive a response using my iPhone. I can connect to the server using:
telnet 123.123.123.1 6000
Trying 123.123.123.1...
Connected to 123.123.123.1.
Escape character is '^]'.
?VERSION
OK
VERSION=PROTOCOL: 1.1.0
?VERSION is my question
OK states it received and understood the question
VERSION= is the response from the server
so I'm trying to do the same thing but with xcode
So I have this in my viewDidLoad
dispatch_queue_t mainQueue = dispatch_get_main_queue();
asyncSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:mainQueue];
asyncSocket.delegate = self;
NSString *host = #"123.123.123.1";
uint16_t port = 6000;
NSLog(#"Connecting to \"%#\" on port %hu...", host, port);
NSError *error = nil;
if (![asyncSocket connectToHost:host onPort:port withTimeout:5.0 error:&error])
{
NSLog(#"Error connecting: %#", error);
}
else
{
NSLog(#"Connecting...");
}
And I have the following code showing it connected
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:
(UInt16)port
{
NSLog(#"socket:%p didConnectToHost:%# port:%hu", sock, host, port);
// We're just going to send a test string to the server.
NSString *myStr = #"?VERSION";
NSData *myData2 = [myStr dataUsingEncoding:NSUTF8StringEncoding];
[asyncSocket writeData:myData2 withTimeout:-1 tag:0];
}
And the following to show it wrote
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
NSLog(#"WRITING");
[asyncSocket readDataToData:[GCDAsyncSocket LFData] withTimeout:-1 tag:0];
}
Sadly this never gets called
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *tempString = [[NSString alloc]initWithData:data
encoding: NSUTF8StringEncoding];
}
I'm lost and really need some assistance
It is because you say write AND read at the same time. First call [asyncSocket writeData:myData2 withTimeout:-1 tag:0]; and in didWriteDataWithTag call [asyncSocket readDataToData:[GCDAsyncSocket LFData] withTimeout:-1 tag:0];. You are on one thread - dispatch_get_main_queue() - it can't do two things at one time.
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
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
here is my code (javascript for node):
var dgram = require('dgram');
var message = new Buffer("why hello beautiful");
var client = dgram.createSocket("udp4");
client.bind(41234);
client.setBroadcast(true);
client.send(message, 0, message.length, 41234, "134.71.147.255");
console.log('msg sent');
client.close();
here is the ifconfig for my computer running node (the only pertinent thing I think -- correct me if im wrong please):
inet addr:134.71.146.49 Bcast:134.71.147.255 Mask:255.255.254.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
The udp broacast is neither recieved on my iOS app nor visible through a packet inspector.
What is going wrong?! The iOS app uses the GCDAsyncUdpSocket framework:
- (void) initUDPlistener {
NSLog(#"initUDPlistener");
udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![udpSocket bindToPort:UDP_PORT error:&error]) //does the port matter? i dont know
{
return;
}
if (![udpSocket beginReceiving:&error])
{
return;
}
[udpSocket enableBroadcast:YES error:nil];
[udpSocket sendData:[self pack:#"iOS to bcast"] toHost:UDP_BCAST_ADDR port:UDP_PORT withTimeout:-1 tag:0];
}
#pragma mark -
#pragma mark Delegate UDP methods
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
NSLog(#"niets.");
NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (msg)
{
NSLog(#"iets gekregen");
}
else
{
NSLog(#"Error convertion");
}
NSLog(#"HMMMM");
}
-(void) udpSocket:(GCDAsyncUdpSocket *) sock didSendDataWithTag:(long)tag {//called. and packet inspector recieves the packet when it is sent OUT from the iOS app.
NSLog(#"written data tag: %ld", tag);
}
-(void) udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address { //never called
NSLog(#"connected to some address");
}
What happens:
"didReceiveData" does not get called from the node broadcast. It gets called when it sends its own message out, however.
the iOS app, on the other hand, successfully broadcasts and i am able to intercept that packet on my packet inspector. The same packet inspector does not show packets that should be originating from Node, however.
what am I doing wrong in node? I think what I am doing in node is the problem.
I tried to connect to the server and send some information to the server(like username, password..), and the server send me back the ID (string type). The problem is I can not get the ID. Could anyone help me? I am beginner in IOS coding. Thanks.
Here is the codes:
After I click the button, it will call my own function to get serverIP which is a string and Port which is a int.
Then that function will call this function to connect the server:
(void)logInCheck {
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
uint16_t port = serverPort;
if (![asyncSocket connectToHost:serverIP onPort:port error:&error])
{
DDLogError(#"Unable to connect to due to invalid configuration: %#", error);
}
else
{
DDLogVerbose(#"Connecting...");
[self passDataToServer];
}
}
//DataPassToServer is a NSString that hold my data
(void)passDataToServer
{
NSData *requestData = [DataPassToServer dataUsingEncoding:NSUTF8StringEncoding];
[asyncSocket writeData:requestData withTimeout:-1.0 tag:0];
[asyncSocket readDataWithTimeout:-1 tag:0];
}
//this function call successfully
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
DDLogVerbose(#"socket:didConnectToHost:%# port:%hu", host, port);
}
//this function call successfully
(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
DDLogVerbose(#"socket:didWriteDataWithTag:");
}
//This function does not run !!! Nothing print out.
(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
DDLogVerbose(#"socket:didReadData:withTag:");
NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"ID = %#",response);
[asyncSocket readDataWithTimeout:-1 tag:0];
}
I don't know about your server implementation but, most implementations would read up to the first newline character before processing the request.
So make sure that your [DataPassToServer dataUsingEncoding:NSUTF8StringEncoding] includes a newline character ("\n") at the end.
Your code looks fine and works for me.