gpt4 book ai didi

objective-c - Objective-C中的线程和套接字

转载 作者:行者123 更新时间:2023-12-03 11:56:16 27 4
gpt4 key购买 nike

注意:我已经编辑了我的问题。我已经连接并执行了第一个回调,但是随后的回调根本不进行。

这是我第一次编写Objective-C(使用GNUstep;它是用于作业)。我已经有了解决方案,但是我正在尝试添加更多的解决方案。该应用程序是一个GUI客户端,可连接到服务器并从中获取数据。多个客户端可以连接到同一服务器。如果任何一个客户端更改了服务器上驻留的数据,则服务器将向所有注册的客户端发送回调。该解决方案最初是用Java(客户端和服务器)实现的,而对于最新的作业,这位教授希望我们为它编写一个Objective-C客户端。他说我们不需要处理回调,但是无论如何我都想尝试。

我正在使用NSThread,我写的东西看起来像这样:

CallbackInterceptorThread.h

#import <Foundation/Foundation.h>
#import "AppDelegate.h"

@interface CallbackInterceptorThread : NSThread {
@private
NSString* clientPort;
AppDelegate* appDelegate;
}

- (id) initWithClientPort: (NSString*) aClientPort
appDelegate: (AppDelegate*) anAppDelegate;
- (void) main;
@end

CallbackInterceptorThread.m
#import <Foundation/Foundation.h>
#import "CallbackInterceptorThread.h"

#define MAXDATASIZE 4096

@implementation CallbackInterceptorThread

- (id) initWithClientPort: (NSString*) aClientPort
appDelegate: (AppDelegate*) anAppDelegate {

if((self = [super init])) {
[clientPort autorelease];
clientPort = [aClientPort retain];
[appDelegate autorelease];
appDelegate = [anAppDelegate retain];
}

return self;
}

- (void) main {

GSRegisterCurrentThread();

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

char* buffer = malloc(MAXDATASIZE);
Cst420ServerSocket* socket = [[Cst420ServerSocket alloc] initWithPort: clientPort];
[socket retain];

NSString* returnString;

while(YES) {
printf("Client waiting for callbacks on port %s\n", [clientPort cString]);

if([socket accept]) {
printf("Connection accepted!\n");
while(YES) {
printf("Inner loop\n");
sleep(1);

returnString = [socket receiveBytes: buffer maxBytes: MAXDATASIZE beginAt: 0];
printf("Received from Server |%s|\n", [returnString cString]);
if([returnString length] > 0) {
printf("Got a callback from server\n");

[appDelegate populateGui];
}

printf("Going to sleep now\n");
sleep(1);
}

[socket close];
}
}
}

@end
Cst420ServerSocket已由讲师提供给我们。看起来像这样:
#import "Cst420Socket.h"
#define PORT "4444"

/**
* Cst420Socket.m - objective-c class for manipulating stream sockets.
* Purpose: demonstrate stream sockets in Objective-C.
* These examples are buildable on MacOSX and GNUstep on top of Windows7
*/

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa){
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

@implementation Cst420ServerSocket

- (id) initWithPort: (NSString*) port{
self = [super init];
int ret = 0;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
const char* portStr = [port UTF8String];
if ((rv = getaddrinfo(NULL, portStr, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
ret = 1;
}else{
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))==-1){
perror("server: socket create error");
continue;
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
#if defined(WINGS)
closesocket(sockfd);
#else
close(sockfd);
#endif
perror("server: bind error");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
ret = 2;
}else{
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("server: listen error");
ret = 3;
}
}
if (ret == 0){
return self;
} else {
return nil;
}
}
}

- (BOOL) accept {
BOOL ret = YES;
#if defined(WINGS)
new_fd = accept(sockfd, NULL, NULL);
#else
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
#endif
if (new_fd == -1) {
perror("server: accept error");
ret = NO;
}
connected = ret;
return ret;
}

- (int) sendBytes: (char*) byteMsg OfLength: (int) msgLength Index: (int) at{
int ret = send(new_fd, byteMsg, msgLength, 0);
if(ret == -1){
NSLog(@"error sending bytes");
}
return ret;
}

- (NSString* ) receiveBytes: (char*) byteMsg
maxBytes: (int) max
beginAt: (int) at {
int ret = recv(new_fd, byteMsg, max-1, at);
if(ret == -1){
NSLog(@"server error receiving bytes");
}
byteMsg[ret+at] = '\0';
NSString * retStr = [NSString stringWithUTF8String: byteMsg];
return retStr;
}

- (BOOL) close{
#if defined(WINGS)
closesocket(new_fd);
#else
close(new_fd);
#endif
connected = NO;
return YES;
}

- (void) dealloc {
#if defined(WINGS)
closesocket(sockfd);
#else
close(sockfd);
#endif
[super dealloc];
}

@end

我们的教授还为我们提供了一个简单的回显服务器和客户端的示例(服务器随即将客户端发送的任何内容吐回来),并且我在线程中使用了相同的模式。

我最初的问题是我的回调拦截器线程不接受来自服务器的任何(回调)连接。服务器说无法连接回客户端(Java的 ConnectException;说“拒绝连接”)。我可以通过更改老师的代码来解决此问题。在 connect函数(未显示)中,他已将提示设置为使用 AF_UNSPEC而不是 AF_INET。因此,Java看到我的本地主机IP以 0:0:0:0:0:0:0:1(IPv6格式)通过。当Java尝试重新连接以发送回调时,它收到一个异常(不确定为什么无法连接到IPv6地址)。

解决此问题后,我再次尝试了我的应用程序,这一次客户端收到了来自服务器的回调。但是,后续的回调无法正常工作。收到第一个回调后,busy-loop继续运行(应有的状态)。但是,当服务器发送第二个回调时,客户端似乎无法读取它。在服务器端,我可以看到它已成功将回调发送给客户端。只是客户端在读取数据时遇到了麻烦。我添加了一些打印语句(参见上文)进行调试,这是我得到的:
Client waiting for callbacks on port 2020
Connection accepted!
Inner loop
Received from Server |A callback from server to 127.0.0.1:2020|
Got a callback from server
Going to sleep now
Inner loop
Received from Server ||
Going to sleep now
Inner loop
Received from Server ||
Going to sleep now
Inner loop
... (and it keeps going regardless of the second callback being sent)

这是我从GUI启动线程的方式:
CallbackInterceptorThread* callbackInterceptorThread = [[CallbackInterceptorThread alloc] initWithClientPort: clientPort appDelegate: self];
[callbackInterceptorThread start];

最佳答案

我想我已经奏效了。因此,从Java端(服务器)开始,这就是我正在做的事情:

Socket socket = new Socket(clientAddress, clientPort);
BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
out.write(("A callback from server to " + clientAddress + ":" + clientPort).getBytes());
out.flush();
out.close();

我在教授的代码中放入了一些调试打印语句,并注意到 receiveBytes中的 recv返回0。 recv的返回值是它收到的消息的长度。因此它收到了一个零长度的字符串。但是返回值0也意味着对等方正确关闭了连接(这正是我从Java端使用 out.close()完成的操作)。因此,我认为如果需要响应第二个回调,则需要再次对连接进行 accept。所以我将忙循环更改为:
printf("Client waiting for callbacks on port %s\n", [clientPort cString]);
while([socket accept]) {
printf("Connection accepted!\n");

returnString = [socket receiveBytes: buffer maxBytes: MAXDATASIZE beginAt: 0];
printf("Received from Server |%s|\n", [returnString cString]);

if([returnString length] > 0) {
printf("Got a callback from server\n");
[appDelegate populateGui];
}
}

[socket close];

这似乎可以解决问题。我不确定这是否是正确的方法,因此我愿意提出改进建议!

关于objective-c - Objective-C中的线程和套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4357783/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com