简单 posix 服务器无法从循环中设置 UILabel
Simple posix server can't set UILabel from loop
我正在尝试将 posix 套接字服务器添加到我的 iOS 应用程序,它将允许 TCP 连接并将缓冲区写入 UILabel 对象作为测试。
我可以让它工作...一次。然后它完成并关闭连接。好的,很容易解决,我只是把它放在一个循环中。现在,每当我将完全相同的代码放入循环中时,由于某种原因它不会更新 UILabel。我实际上并不需要它来更新 UILabel,这只是一个确保服务器正常工作的测试......但这让我很紧张。我将它从 while 循环中取出,它起作用了,我把它放回去,除了 UILabel setText 调用之外的所有东西都起作用了。
此外,还有另外两个小问题:我无法弄清楚客户端断开连接后如何退出循环,而且我不确定退出时如何正确关闭端口,我必须不断更改端口号,因为它不能绑定。
-(void)viewDidLoad
NSThread *listenThread = [[NSThread alloc] initWithTarget:self selector:@selector(createPosixServer) object:nil];
[listenThread start];
-(void)createPosixServer
//declarations
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
NSString *nsbuffer;
//bind and listen on socket
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
NSLog(@"Error while calling socket()");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 1818;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
NSLog(@"ERROR on binding");
}
listen(sockfd, 5);
NSLog(@"Begin listen loop");
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
NSLog(@"ERROR on accept");
}
while(true) {
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) {
NSLog(@"ERROR reading from socket");
}
if (n > 0) {
nsbuffer = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding];
[_lblStatus setText:nsbuffer];
NSLog(@"You sent %@", nsbuffer);
}
NSLog(@"Finished listen loop");
sleep(1);
}
close(newsockfd);
close(sockfd);
NSLog(@"Socket closed");
createPosixServer
在后台线程上是 运行。从后台线程更新 UI 是不安全的。 UIKit有时会工作,有时只是不理你。您需要将更新标签的调用分派到主线程,如下所示:
typeof(self) __weak weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.lblStatus.text = nsbuffer;
});
回答附带问题:当客户端断开连接时,您想要关闭为该连接接受的套接字(您的 newsockfd
),但您不想关闭您的侦听器 sockfd
直到你拆除整个服务。
要退出循环,只需这样做:
if (n < 0) {
NSLog(@"ERROR reading from socket");
break;
}
尽管您可能也想检查该块中的 errno
,因为您可能会根据错误需要不同的行为。
删除sleep(1)
,那对你没有任何好处。 read
调用会阻塞,不用睡觉了。
我正在尝试将 posix 套接字服务器添加到我的 iOS 应用程序,它将允许 TCP 连接并将缓冲区写入 UILabel 对象作为测试。
我可以让它工作...一次。然后它完成并关闭连接。好的,很容易解决,我只是把它放在一个循环中。现在,每当我将完全相同的代码放入循环中时,由于某种原因它不会更新 UILabel。我实际上并不需要它来更新 UILabel,这只是一个确保服务器正常工作的测试......但这让我很紧张。我将它从 while 循环中取出,它起作用了,我把它放回去,除了 UILabel setText 调用之外的所有东西都起作用了。
此外,还有另外两个小问题:我无法弄清楚客户端断开连接后如何退出循环,而且我不确定退出时如何正确关闭端口,我必须不断更改端口号,因为它不能绑定。
-(void)viewDidLoad
NSThread *listenThread = [[NSThread alloc] initWithTarget:self selector:@selector(createPosixServer) object:nil];
[listenThread start];
-(void)createPosixServer
//declarations
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
NSString *nsbuffer;
//bind and listen on socket
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
NSLog(@"Error while calling socket()");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 1818;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
NSLog(@"ERROR on binding");
}
listen(sockfd, 5);
NSLog(@"Begin listen loop");
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
NSLog(@"ERROR on accept");
}
while(true) {
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) {
NSLog(@"ERROR reading from socket");
}
if (n > 0) {
nsbuffer = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding];
[_lblStatus setText:nsbuffer];
NSLog(@"You sent %@", nsbuffer);
}
NSLog(@"Finished listen loop");
sleep(1);
}
close(newsockfd);
close(sockfd);
NSLog(@"Socket closed");
createPosixServer
在后台线程上是 运行。从后台线程更新 UI 是不安全的。 UIKit有时会工作,有时只是不理你。您需要将更新标签的调用分派到主线程,如下所示:
typeof(self) __weak weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.lblStatus.text = nsbuffer;
});
回答附带问题:当客户端断开连接时,您想要关闭为该连接接受的套接字(您的 newsockfd
),但您不想关闭您的侦听器 sockfd
直到你拆除整个服务。
要退出循环,只需这样做:
if (n < 0) {
NSLog(@"ERROR reading from socket");
break;
}
尽管您可能也想检查该块中的 errno
,因为您可能会根据错误需要不同的行为。
删除sleep(1)
,那对你没有任何好处。 read
调用会阻塞,不用睡觉了。