zoukankan      html  css  js  c++  java
  • UNP学习笔记二简单的并发服务器(concurrent servers)

    1、一个典型的tcp client/server调用的函数顺序如下:

    2、tcp server会在accept处等待客户端连接;而udp server则会在recvfrom函数处等待客户端连接。

    3、一个简单的并发服务器使用fork和exec来完成客户端的并发请求处理。fork以后,父进程关闭connect fd,子进程关闭listen fd,子进程在完成逻辑处理后关闭 connent fd。

    #include        "unp.h"

    int main(int argc, char **argv)
    {
            int                                     listenfd, connfd;
            pid_t                           childpid;
            socklen_t                       clilen;
            struct sockaddr_in      cliaddr, servaddr;

            listenfd = Socket(AF_INET, SOCK_STREAM, 0);

            bzero(&servaddr, sizeof(servaddr));
            servaddr.sin_family      = AF_INET;
            servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
            servaddr.sin_port        = htons(SERV_PORT);

            Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

            Listen(listenfd, LISTENQ);

            for ( ; ; ) {
                    clilen = sizeof(cliaddr);
                    connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);

                    if ( (childpid = Fork()) == 0) {        /* child process */
                            Close(listenfd);        /* close listening socket */
                            str_echo(connfd);       /* process the request */
                            exit(0);
                    }
                    Close(connfd);                  /* parent closes connected socket */
            }
    }

    以下小结来自:http://blog.chinaunix.net/u/21000/showart.php?id=143807

    面向连接的编程模式——TCP套接字

    服务器端编程模板:

    socket();   //创建套接字,同时也是一个文件描述符

    bind();     //邦定套接字和服务器端口(包括IP地址和端口号),邦定之前要先初始化IP地址和端口

    listen();   //监听该端口

    accept();   //一般在一个while(1)循环体里。如果有连接请求则接受请求,返回一个新的与客户端绑定了的套接字(称为连接套接字,与前面的监听套接字相对),并产生一个新的进程或线程处理该客户的请求

    recv() or send();//与客户端交换数据,或处理程序,一般在新产生的的进程或线程里的一个循环体里

    close();    //别忘了关闭套接字,当然,如果中途发生错误,退出之前也应该关闭套接字

    客户端模版:

    socket();

    connect();  //向客户端发送连接请求,客户端是不用邦定的,由系统自动为套接字分配端口,该函数把本地IP和该线程的端口发送给服务器

    send() or recv(); //与服务器交换数据

    close();          //同上

    面向无连接的编程模式——UDP套接字

    服务器端编程模版:

    socket();

    bind();      //绑定监听端口

    recvfrom();  //堵塞,直到接收到数据报

    sendto();    //处理客户数据或作出回应

    close();

    客户端编程模版:

    socket();

    sendto();

    recvfrom();  //堵塞,直到接收到回应,还要判断是不是特定服务器的回应,一般是在一个while循环里。

    close();

    对比TCP和UDP,前者需要一个特定的端口作为监听端口,专门接收来自客户端的服务请求。send()中不用包含目标IP地址和端口,因为客户和服务器已经建立了连接,直接对连接套接口操作就可以了,而recv()也不用存放信息的IP地址和端口。而后者不需要监听端口,只需要一个端口接收数据报就可以了,但sendto()需要目标IP地址和端口,而recv()也需要存放IP和端口的空间。

    另外,应用UDP的客户端还需要判断接收到的数据是不是特定服务器的回复,这需要比较IP地址和端口。

    并发的实现方法

    应用多进程:

    当accept()接收到新的连接请求,应用fork()系统调用,产生子进程处理客户请求。

    fork()函数原型:

    #include <sys/types.h>

    #include <unistd.h>

    pid_t fork(void)

    返回值:子进程为0,父进程为子进程的ID,出错为-1

    子进程是父进程的副本,子进程中有父进程的数据空间、堆栈的一份copy,注意是copy而不是共享,这是多进程与多线程最主要的区别,也导致截然不同的处理方式。

    一般可以根据fork()的返回值来使父、子进程进行不同的处理,如:

    while (1){
    if((connectSoc = accept(listenSoc,(struct sockaddr *)&client, &sin_size)) == -1){
      perror("accept() error!\n");
      close(listenSoc);
      exit(1);
    }
    pid = fork();
    if(pid > 0){      //父进程处理程序,继续接收新的客户请求
      close(connectSoc);
      continue;
    }
    else if (pid == 0){//子进程处理程序
      close(listenSoc);
      printf("You got a connection from %s\n",inet_ntoa(client.sin_addr));
      if(send(connectSoc,Msg,25,0) == -1){
       perror("send() error!\n");
      }
      close(connectSoc);
      exit(1);
    }
    else {
      printf("fork() error!\n");
      close(listenSoc);
      exit(1);
    }
    }

  • 相关阅读:
    node.js 安装
    spring mvc 表单标签
    配置文件 .properties 的使用。
    angular 参考文档
    bootStrap 教程 文档
    idea 安装 破解方法
    restful 注解 总结 (比较完整的):http://www.xuetimes.com/archives/388 , https://www.cnblogs.com/chen-lhx/p/5599806.html
    apo 简单参考
    jsonUtils&&Json、Xml转换工具Jackson使用
    restful 分风格
  • 原文地址:https://www.cnblogs.com/shanks/p/1503242.html
Copyright © 2011-2022 走看看