Objective-C字符串编码问题(objective-C string encoding problem)
好吧,我对C套接字相当陌生,但我只需要做一些简单的sendto()和recvfrom()调用,使用多播套接字在网络中获取一个字符串。 在环顾四周并阅读了几个指南(包括Beej's)后,我发现下面的代码可以监听通过多播套接字发送的消息(这正是我所需要的)。 程序运行良好时,它在主要,但我的问题出现时,我把它放在一个方法(即方法称为“listenForPackets”)在我的项目中的其他地方,并试图运行它在runloop的另一个线程。 经过调试后,问题归结为变量“mc_addr_str”,该变量在main方法中被赋值为等于argv [1]。
#include <sys/types.h> // for type definitions #include <sys/socket.h> // for socket API calls #include <netinet/in.h> // for address structs #include <arpa/inet.h> // for sockaddr_in #include <stdio.h> // for printf() and fprintf() #include <stdlib.h> // for atoi() #include <string.h> // for strlen() #include <unistd.h> // for close() #define MAX_LEN 1024 // maximum receive string size #define MIN_PORT 1024 // minimum port allowed #define MAX_PORT 65535 // maximum port allowed int main(int argc, char *argv[]) { int sock; // socket descriptor int flag_on = 1; // socket option flag struct sockaddr_in mc_addr; // socket address structure char recv_str[MAX_LEN+1]; // buffer to receive string int recv_len; // length of string received struct ip_mreq mc_req; // multicast request structure char* mc_addr_str; // multicast IP address unsigned short mc_port; // multicast port struct sockaddr_in from_addr; // packet source unsigned int from_len; // source addr length // validate number of arguments if (argc != 3) { fprintf(stderr, "Usage: %s <Multicast IP> <Multicast Port>\n", argv[0]); exit(1); } mc_addr_str = argv[1]; // arg 1: multicast ip address mc_port = atoi(argv[2]); // arg 2: multicast port number // validate the port range if ((mc_port < MIN_PORT) || (mc_port > MAX_PORT)) { fprintf(stderr, "Invalid port number argument %d.\n", mc_port); fprintf(stderr, "Valid range is between %d and %d.\n", MIN_PORT, MAX_PORT); exit(1); } // create socket to join multicast group on if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("socket() failed"); exit(1); } // set reuse port to on to allow multiple binds per host if ((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag_on, sizeof(flag_on))) < 0) { perror("setsockopt() failed"); exit(1); } // construct a multicast address structure memset(&mc_addr, 0, sizeof(mc_addr)); mc_addr.sin_family = AF_INET; mc_addr.sin_addr.s_addr = htonl(INADDR_ANY); mc_addr.sin_port = htons(mc_port); // bind multicast address to socket if ((bind(sock, (struct sockaddr *) &mc_addr, sizeof(mc_addr))) < 0) { perror("bind() failed"); exit(1); } // construct an IGMP join request structure mc_req.imr_multiaddr.s_addr = inet_addr(mc_addr_str); mc_req.imr_interface.s_addr = htonl(INADDR_ANY); // send an ADD MEMBERSHIP message via setsockopt if ((setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*) &mc_req, sizeof(mc_req))) < 0) { perror("setsockopt() failed"); exit(1); } for (;;) { // loop forever // clear the receive buffers & structs memset(recv_str, 0, sizeof(recv_str)); from_len = sizeof(from_addr); memset(&from_addr, 0, from_len); // block waiting to receive a packet if ((recv_len = recvfrom(sock, recv_str, MAX_LEN, 0, (struct sockaddr*)&from_addr, &from_len)) < 0) { perror("recvfrom() failed"); exit(1); } // output received string printf("Received %d bytes from %s: ", recv_len, inet_ntoa(from_addr.sin_addr)); printf("%s", recv_str); } // send a DROP MEMBERSHIP message via setsockopt if ((setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void*) &mc_req, sizeof(mc_req))) < 0) { perror("setsockopt() failed"); exit(1); } close(sock); }
现在,通过另一个SO成员的帮助,我有一个方法将IP地址作为NSString返回给我(我在我的程序的其他地方也使用它,所以我需要保持它返回NSString)。
-(NSString *)getIPAddress { NSString *address = @"error"; struct ifaddrs *interfaces; // = NULL; struct ifaddrs *temp_addr; // = NULL; int success = 0; // retrieve the current interfaces - returns 0 on success success = getifaddrs(&interfaces); if (success == 0) { // Loop through linked list of interfaces temp_addr = interfaces; while(temp_addr != NULL) { if(temp_addr->ifa_addr->sa_family == AF_INET) { // Check if interface is en0 which is the wifi connection on the iPhone if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) { // Get NSString from C String address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; } } temp_addr = temp_addr->ifa_next; } } // Free memory freeifaddrs(interfaces); return address; }
我以为我可以做一个简单的小转换
mc_addr_str = (someConversion)getIPAddress;
我到目前为止是:
NSString *ipAddress = [[NSString alloc] initWithString:self.getIPAddress]; mc_addr_str = [ipAddress cStringUsingEncoding:[NSString defaultCStringEncoding]];
当我这样做时,程序会将它传递给setsockopt调用,然后以-1的错误代码失败(我假设这是一个通用错误代码,可让程序知道发生了什么不愉快的事情并需要中止)。 另外,当我在前面的语句中分配mc_addr_str时,我会得到
warning: assignment discards qualifiers from pointer target type
我不确定现在我的问题在哪里。 在分配给mc_addr_str期间,我有铸造错误还是使用了错误的编码? 任何输入是赞赏!
Ok, I'm fairly new to C sockets but I just need to do some simple sendto() and recvfrom() calls to get a string out across a network, using multicast sockets. After looking around and reading several guides (including Beej's), I found the code below which does the job of listening for messages sent over a multicast socket (which is what I need). The program runs fine when it is in main, but my problem arises when I put it in a method (i.e. a method called "listenForPackets") elsewhere in my project and attempt to run it in another thread on a runloop. After debugging though, the problem comes down to the variable "mc_addr_str" which is assigned to equal argv[1] in the main method.
#include <sys/types.h> // for type definitions #include <sys/socket.h> // for socket API calls #include <netinet/in.h> // for address structs #include <arpa/inet.h> // for sockaddr_in #include <stdio.h> // for printf() and fprintf() #include <stdlib.h> // for atoi() #include <string.h> // for strlen() #include <unistd.h> // for close() #define MAX_LEN 1024 // maximum receive string size #define MIN_PORT 1024 // minimum port allowed #define MAX_PORT 65535 // maximum port allowed int main(int argc, char *argv[]) { int sock; // socket descriptor int flag_on = 1; // socket option flag struct sockaddr_in mc_addr; // socket address structure char recv_str[MAX_LEN+1]; // buffer to receive string int recv_len; // length of string received struct ip_mreq mc_req; // multicast request structure char* mc_addr_str; // multicast IP address unsigned short mc_port; // multicast port struct sockaddr_in from_addr; // packet source unsigned int from_len; // source addr length // validate number of arguments if (argc != 3) { fprintf(stderr, "Usage: %s <Multicast IP> <Multicast Port>\n", argv[0]); exit(1); } mc_addr_str = argv[1]; // arg 1: multicast ip address mc_port = atoi(argv[2]); // arg 2: multicast port number // validate the port range if ((mc_port < MIN_PORT) || (mc_port > MAX_PORT)) { fprintf(stderr, "Invalid port number argument %d.\n", mc_port); fprintf(stderr, "Valid range is between %d and %d.\n", MIN_PORT, MAX_PORT); exit(1); } // create socket to join multicast group on if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("socket() failed"); exit(1); } // set reuse port to on to allow multiple binds per host if ((setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag_on, sizeof(flag_on))) < 0) { perror("setsockopt() failed"); exit(1); } // construct a multicast address structure memset(&mc_addr, 0, sizeof(mc_addr)); mc_addr.sin_family = AF_INET; mc_addr.sin_addr.s_addr = htonl(INADDR_ANY); mc_addr.sin_port = htons(mc_port); // bind multicast address to socket if ((bind(sock, (struct sockaddr *) &mc_addr, sizeof(mc_addr))) < 0) { perror("bind() failed"); exit(1); } // construct an IGMP join request structure mc_req.imr_multiaddr.s_addr = inet_addr(mc_addr_str); mc_req.imr_interface.s_addr = htonl(INADDR_ANY); // send an ADD MEMBERSHIP message via setsockopt if ((setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*) &mc_req, sizeof(mc_req))) < 0) { perror("setsockopt() failed"); exit(1); } for (;;) { // loop forever // clear the receive buffers & structs memset(recv_str, 0, sizeof(recv_str)); from_len = sizeof(from_addr); memset(&from_addr, 0, from_len); // block waiting to receive a packet if ((recv_len = recvfrom(sock, recv_str, MAX_LEN, 0, (struct sockaddr*)&from_addr, &from_len)) < 0) { perror("recvfrom() failed"); exit(1); } // output received string printf("Received %d bytes from %s: ", recv_len, inet_ntoa(from_addr.sin_addr)); printf("%s", recv_str); } // send a DROP MEMBERSHIP message via setsockopt if ((setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void*) &mc_req, sizeof(mc_req))) < 0) { perror("setsockopt() failed"); exit(1); } close(sock); }
Now, via help from another SO member, I have a method that will return the IPaddress to me as a NSString (I'm using it elsewhere in my program also, so I need to keep it returning NSString).
-(NSString *)getIPAddress { NSString *address = @"error"; struct ifaddrs *interfaces; // = NULL; struct ifaddrs *temp_addr; // = NULL; int success = 0; // retrieve the current interfaces - returns 0 on success success = getifaddrs(&interfaces); if (success == 0) { // Loop through linked list of interfaces temp_addr = interfaces; while(temp_addr != NULL) { if(temp_addr->ifa_addr->sa_family == AF_INET) { // Check if interface is en0 which is the wifi connection on the iPhone if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) { // Get NSString from C String address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; } } temp_addr = temp_addr->ifa_next; } } // Free memory freeifaddrs(interfaces); return address; }
I thought I could just do a simple little conversion
mc_addr_str = (someConversion)getIPAddress;
What I have so far is:
NSString *ipAddress = [[NSString alloc] initWithString:self.getIPAddress]; mc_addr_str = [ipAddress cStringUsingEncoding:[NSString defaultCStringEncoding]];
When I do this, the program makes it to the setsockopt call and then fails with an error code of -1 (I assume that's a general error code that lets the program know something bad happened and needs to abort). Also, when I am assigning mc_addr_str in the previous statement, I get
warning: assignment discards qualifiers from pointer target type
I'm not sure where my problem is arising from now. Do I have a casting error during the assignment to mc_addr_str or did I use the wrong encoding? Any input is appreciated!
原文:https://stackoverflow.com/questions/1169043