我已经使用 GCDAsyncsocket 库编写了一个单例类,以使用 Bonjour 与具有相同服务的任何其他设备建立连接。
在一台设备上,我正在使用它的方法“startPublishing”使其成为主机(服务器),从另一台设备(客户端)上的应用程序我调用“StartBrowsing"以找出网络中可用的设备。当用户选择该网络中的任何服务时,我将调用方法“initConnectionWithService”,该方法通过解析要连接的 NetService 地址来启动连接流。
BonjourUtilClass.h
@interface BonjourUtilClass : NSObject<GCDAsyncSocketDelegate,NSNetServiceDelegate,NSNetServiceBrowserDelegate>{
NSNetService *netServiceToPublish;
GCDAsyncSocket *socketPub;
NSNetServiceBrowser *netServiceToBrowse;
GCDAsyncSocket *socketSub;
NSMutableArray *mutArrServices;
GCDAsyncSocket *socketConnected;
}
+(id)sharedInstance;
-(void)startPublishing;
-(void)startBrowsing;
-(void)initConnectionWithService:(NSNetService*)netServiceToConnect;
-(void)disconnectWithCurrent;
@end
BonjourUtilClass.m
static BonjourUtilClass *sharedObject = nil;
@implementation BonjourUtilClass
+(id)sharedInstance{
if(!sharedObject){
sharedObject = [[BonjourUtilClass alloc]init];
}
return sharedObject;
}
#pragma mark - Browsing
-(void)startBrowsing{
if(mutArrServices){
[mutArrServices removeAllObjects];
}else{
mutArrServices = [NSMutableArray array];
}
netServiceToBrowse = [[NSNetServiceBrowser alloc]init];
netServiceToBrowse.delegate= self;
[netServiceToBrowse searchForServicesOfType:@"_mrug._tcp" inDomain:@"local."];
}
-(void)stopBrowsing{
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
[mutArrServices addObject:aNetService];
if(!moreComing) {
// Sort Services
[mutArrServices sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]];
// Update Table View
[[NSNotificationCenter defaultCenter]postNotificationName:kNotifyReloadList object:mutArrServices];
}
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing{
[mutArrServices removeObject:aNetService];
if(!moreComing) {
// Sort Services
[mutArrServices sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]];
// Update Table View
[[NSNotificationCenter defaultCenter]postNotificationName:kNotifyReloadList object:mutArrServices];
}
}
-(void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)aNetServiceBrowser{
NSLog(@"Search browser Did STOP search..");
[self stopBrowsing];
}
-(void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict{
NSLog(@"Search browser Did not search..");
[self stopBrowsing];
}
#pragma mark - NetService Delegate
-(void)startPublishing{
socketPub = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *aError;
if([socketPub acceptOnPort:0 error:&aError]){
netServiceToPublish = [[NSNetService alloc]initWithDomain:@"local." type:@"_mrug._tcp" name:@"" port:socketPub.localPort];
netServiceToPublish.delegate =self;
[netServiceToPublish publish];
}else{
NSLog(@"Unable To Create Socket..");
}
}
//NetService Delegates
-(void)netService:(NSNetService *)sender didNotPublish:(NSDictionary *)errorDict{
NSLog(@"Failed To Publish : Domain=%@ type=%@ name=%@ info=%@",sender.domain,sender.type,sender.name,errorDict);
}
-(void)netServiceDidPublish:(NSNetService *)sender{
NSLog(@"Service Published : Domain=%@ type=%@ name=%@ port=%li",sender.domain,sender.type,sender.name,(long)sender.port);
}
//Resolving Address
- (void)netService:(NSNetService *)service didNotResolve:(NSDictionary *)errorDict {
[service setDelegate:nil];
}
- (void)netServiceDidResolveAddress:(NSNetService *)service {
// Connect With Service
if ([self connectWithService:service]){
NSLog(@"Did Connect with Service: domain(%@) type(%@) name(%@) port(%i)", [service domain], [service type], [service name], (int)[service port]);
} else {
NSLog(@"Unable to Connect with Service: domain(%@) type(%@) name(%@) port(%i)", [service domain], [service type], [service name], (int)[service port]);
}
}
#pragma mark - GCDSocket delegates
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
NSLog(@"Accepted new Socket: HOST : %@ , CONNECTION PORT :%li",newSocket.connectedHost,(long)newSocket.connectedPort);
}
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
NSLog(@"Socket DisConnected %s,%@,%@",__PRETTY_FUNCTION__, sock,err);
if(socketPub == sock){
socketPub.delegate = nil;
socketPub = nil;
}else if (socketConnected == sock){
socketConnected.delegate=nil;
socketConnected = nil;
}
}
- (void)socket:(GCDAsyncSocket *)socket didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(@"Socket Did Connect to Host: %@ Port: %hu", host, port);
// Start Reading
[socket readDataToLength:sizeof(uint64_t) withTimeout:-1.0 tag:0];
}
#pragma mark - Connection Methods
-(void)disconnectWithCurrent{
if(socketConnected){
[socketConnected disconnect];
socketConnected.delegate = nil;
socketConnected = nil;
}
}
-(void)initConnectionWithService:(NSNetService*)netServiceToConnect{
// Resolve Service
[netServiceToConnect setDelegate:self];
[netServiceToConnect resolveWithTimeout:30.0];
}
- (BOOL)connectWithService:(NSNetService *)service {
BOOL _isConnected = NO;
// Copy Service Addresses
NSArray *addresses = [[service addresses] mutableCopy];
if (!socketConnected || ![socketConnected isConnected]) {
// Initialize Socket
socketConnected = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
// Connect
while (!_isConnected && [addresses count]) {
NSData *address = [addresses objectAtIndex:0];
NSError *error = nil;
if ([socketConnected connectToAddress:address error:&error]) {
_isConnected = YES;
} else if (error) {
NSLog(@"Unable to connect to address. Error %@ with user info %@.", error, [error userInfo]);
}
}
} else {
_isConnected = [socketConnected isConnected];
}
return _isConnected;
}
@end
但是,在执行上述事情时,非常意外的事情发生了,作为客户端的设备正在 didConnectedToHost 中获得回调,并且立即,另一个回调即将到来,它位于 didDisconnected
客户端设备上的日志
2014-12-11 15:16:32.512 GCDSocketDemo[1419:71238] Did Connect with Service: domain(local.) type(_mrug._tcp.) name(ind506Bonjour) port(52026)
2014-12-11 15:16:32.659 GCDSocketDemo[1419:71238] Socket Did Connect to Host: 10.2.4.130 Port: 52026
2014-12-11 15:16:32.660 GCDSocketDemo[1419:71238] -[AppDelegate socketDidDisconnect:withError:],<GCDAsyncSocket: 0x7fa0a3533b90>,Error Domain=GCDAsyncSocketErrorDomain Code=7 "Socket closed by remote peer" UserInfo=0x7fa0a3532f70 {NSLocalizedDescription=Socket closed by remote peer}
在服务器设备上登录
2014-12-11 15:15:48.546 GCDSockrtMacDemo[1397:70851] Service Published : Domain=local. type=_mrug._tcp. name=ind506Bonjour port=52026
2014-12-11 15:16:32.585 GCDSockrtMacDemo[1397:70851] Accepted new Socket: HOST : 10.2.4.130 , CONNECTION PORT :52029
2014-12-11 15:16:32.613 GCDSockrtMacDemo[1397:70851] -[BonjourUtilClass socketDidDisconnect:withError:],(null),(null)
最佳答案
Paulw11 的评论帮助我找到了解决方案。实际上我在客户端存储了Socket,但是忘记在回调方法“didAcceptNewSocket”中存储获取新Socket的引用。
所以方法 didAcceptNewSocket 应该如下所示:
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
NSLog(@"Accepted new Socket: HOST : %@ , CONNECTION PORT :%li",newSocket.connectedHost,(long)newSocket.connectedPort);
socketConnected = newSocket;
}
这样在这个方法中接收到的newSocket可以被持久化以便进一步的通信。在较早的情况下,它在方法结束时释放。
关于ios - 连接后立即断开与服务器的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27419679/
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo
我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除