iOS and OS X Network Programming Cookbook |Creating an echo server(BSD)

11 篇文章 0 订阅

对于这本书没有过实战经验,学起来非常沉闷,搭建服务器应该是用得最多的了,因为我不会用其他的方法搭建

在整个学编程的过程中也是这样,有点点实战就加点血,多看点这样不知道怎么用但是又不得不看不得不知道的东西就掉点血



建立socket,需要调用socket(), bind()和listen()都不能出错。

在书中的案例中使用的是IPV4和TCP创建的socket(IPV6换成AF_INET6, UDP换成SOCK_DGRAM)

self.listenfd = socket(AF_INET, SOCK_STREAM, 0)

然后将socket与一个sockaddr_in structure(servaddr)绑定

bind(self.listenfd, (struct sockaddr *)&servaddr,sizeof(servaddr)
在此之前需要清除servaddr的内存,并对其进行设置

memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);

port值是给定的,INADDR_ANY的意思是将socket于任意接口绑定

htonl()和htons()是将host byte order 转换为 network byte order,byte order就是计算机读取123的顺序是123还是321


绑定成功后就可以进行监听了,第二个参数设定的是最大鉴定数,这里是1024

listen (self.listenfd, LISTENQ)

完整代码

-(instancetype)initOnPort:(int)port {
    self = [super init];
    if (self) {
        struct sockaddr_in servaddr;
        
        self.errorCode = NOERROR;
        if ( (self.listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            self.errorCode = SOCKETERROR;
        else {
            memset(&servaddr, 0, sizeof(servaddr));
            servaddr.sin_family = AF_INET;
            servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
            servaddr.sin_port = htons(port);
            
            if (bind(self.listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) <0) {
                self.errorCode = BINDERROR;
            } else {
                
                if ((listen (self.listenfd, LISTENQ)) <0) {
                    self.errorCode = LISTENERROR;
                }
            }
        }
    }
    return self;
}


listenfd代表socket descriptor,赋值给下一个方法

现在我们就有了个在监听port上的新连接的socket,在新连接建立好后改干点有意思的事情

这就是接下来这个方法干的事,监听新连接,并且位置创建一个新线程

-(void)echoServerListenWithDescriptor:(int)lfd {
    int connfd;
    socklen_t clilen;
    struct sockaddr_in cliaddr;
    char buf[MAXLINE];
    
    for (;;) {
        clilen = sizeof(cliaddr);
        if ((connfd = accept(lfd, (struct sockaddr *)&cliaddr, &clilen))<0) {
            if (errno != EINTR) {
                self.errorCode = ACCEPTINGERROR;
                NSLog(@"Error accepting connection");
            }
        } else {
            self.errorCode = NOERROR;
            NSString *connStr = [NSString stringWithFormat:@"Connection from %s, port %d", inet_ntop(AF_INET, &cliaddr.sin_addr,buf, sizeof(buf)),ntohs(cliaddr.sin_port)];
            NSLog(@"%@", connStr);
            
            //Multi-threaded
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
                [self strEchoServer:@(connfd)];
            });
            
        }
    }
}
accept()查明并且初始化在监听的socket上的链接,建立一个新连接就产生一个新的socket descriptor(connfd),链接成功输出链接地址和端口

如果不用GCD,服务器一次只能应付一个链接

strEchoServer()对写入文字信息进行监听,并反馈给客户端

-(void)strEchoServer:(NSNumber *) sockfdNum {
         ssize_t n;
         char buf[MAXLINE];
         int sockfd = [sockfdNum intValue];
         while ((n=recv(sockfd, buf, MAXLINE -1,0)) > 0) {
             [self written:sockfd char:buf size:n];
             buf[n]='\0';
             NSLog(@"%s",buf);
             [[NSNotificationCenter defaultCenter] postNotificationName:
   @"posttext" object:[NSString stringWithCString:buf encoding:NSUTF8Str
   ingEncoding]];
         }
         NSLog(@"Closing Socket");
         close(sockfdNum);
}

接受信息后再写入,对于客户端来说就是发出信息后再接收相同的信息。

recv()进行接受信息,存储在buf中,n的返回值是0就是没有连接状态,负数是错误,0he负数都会关闭socket,成功的话n的值是接收信息的字节数


-(ssize_t) written:(int)sockfdNum char:(const void *)vptr
   size:(size_t)n {
        size_t    nleft;
        ssize_t    nwritten;
        const char  *ptr;
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
          if ( (nwritten = write(sockfdNum, ptr, nleft)) <= 0) {
            if (nwritten < 0 && errno == EINTR)
        nwritten = 0;
      else
return -1;
    nleft -= nwritten;
    ptr   += nwritten;
  }
return(n); }

write()方法与recv类似,ptr是一个指针指向写入的text,每次写入指针都向后移动,nleft就是要写入的字节数,nwritten是返回的已经写入的字节数


可以通过终端调用telnet localhost (port,自己设定的port值,大于1024,小于65535)

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.m或d论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 、1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值