zoukankan      html  css  js  c++  java
  • Socket编程回顾,一个最简单服务器程序

    第一次接触服务器是快毕业的时候,是不是有点晚(# ̄ω ̄),这也导致工作方向一直没考虑网络编程这块,做了好多其他没啥“意思”的技术。

    之前看到一篇博文提到程序猿80%都是庸才,10%是人才,10%是天才,深有感触。仔细想想自己是不是也是还在那80%里面挣扎?一个抱怨这抱怨那的trouble maker,写着烂的掉渣的代码,永远在别人身后不思进取,给剩下的20%的同事埋雷。

    扯远了,重新回顾Socket,温习下Linux内核是怎么处理Socket的吧。

    文件描述符,在网络编程中经常提及这个词,当时初学时一直就这么叫着,现在回头看。不过对Linux内核分配的IO的称谓而已,套接字(Socket)本质上就是文件描述符,为何加上文件两个字?因为Linux万物皆文件啊!。在TCP整个通讯过程,有多个文件描述符需要处理。

    Listenfd:监听描述符

    Connectfd:请求连接描述符

    Accept:接受连接描述符

    Read/Write/Recv/Send…:IO描述符(本文不详细阐述)

    服务器建立连接的流程和涉及到的函数:socket()、bind()、listen()、accept()、connect()、close()。

    结构体struct sockaddr_in :网络通讯五元组,本端IP,本端端口、对端IP、对端端口、协议类型。

    int socket(int domain, int type, int protocol);

    创建一个套接字,并且设置该套接字协议类型。

    image

    int bind(SOCKET socket, const struct sockaddr* address, socklen_t address_len);

    为套接字绑定IP和端口。

    image

    int listen(int socket, int backlog);

    listen通过socket套接字和该套接字绑定的IP信息在内核开启监听,并且返回监听描述符。

    此处监听工作交给内核处理,代码本身不阻塞,但内核对应端口一直在做监听工作。同时维护两个连接队列,大小由backlog决定。

     
    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    发送连接请求,代码默认阻塞。

    image

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

    接受连接请求,代码默认阻塞。

    accept实际上是在从内核listen维护的就绪队列中取描述符。

     

    int close(int fd);

    关闭描述符。listen描述符和accept描述符是完全独立的,关闭其中一个互不影响。

    image

    这里再详细阐述listen()调用后,内核是如何维护两个连接队列的。其实维护的就是熟悉的三次握手过程。

    image

    Client请求时间是不确定的,当多个请求到Server时,处于请求队列,等待listen的端口逐个处理至就绪队列。

    connect处于阻塞态等待请求从listen的就绪队列被accept调度返回具体用于数据传输的accept_fd描述符。

    accept处于阻塞态,当请求队列为空或处理完毕时。

    由此可知,三次握手由connet发起,accept结束,途中经历listen的队列维护。

    下面附上整个流程代码。

     1 /* File Name: server.c */
     2 #include<stdio.h> 
     3 #include<stdlib.h>  
     4 #include<string.h>  
     5 #include<errno.h>  
     6 #include<sys/types.h>  
     7 #include<sys/socket.h>  
     8 #include<sys/unistd.h>
     9 #include<netinet/in.h>  
    10 const int DEFAULT_PORT = 2500;  
    11 const int BUFFSIZE = 1024;
    12 const int MAXLINK = 10;
    13 
    14 int main(int argc, char** argv)  
    15 {  
    16     int    socket_fd, connect_fd;  
    17     struct sockaddr_in servaddr;  
    18     char buff[BUFFSIZE];    
    19     
    20     if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    21     {  
    22         printf("create socket error: %s(errno: %d)
    ",strerror(errno),errno);  
    23         exit(0);  
    24     } 
    25     
    26     memset(&servaddr, 0, sizeof(servaddr));  
    27     servaddr.sin_family = AF_INET;  
    28     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    29     servaddr.sin_port = htons(DEFAULT_PORT);
    30   
    31     if (bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
    32     {  
    33         printf("bind socket error: %s(errno: %d)
    ",strerror(errno),errno);  
    34         exit(0);  
    35     }  
    36     
    37     if (listen(socket_fd, MAXLINK) == -1)
    38     {  
    39         exit(0);  
    40     }   
    41 
    42     if ((connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1)
    43     {  
    44         exit(0);  
    45     } 
    46     
    47     while(1)
    48     {   
    49         memset(&buff,'', sizeof(buff));  
    50         
    51         recv(connect_fd, buff, BUFFSIZE - 1, 0);  
    52         send(connect_fd, buff, BUFFSIZE - 1, 0); 
    53         
    54         printf("recv msg from client: %s
    ", buff);  
    55     }  
    56     close(connect_fd);    
    57     close(socket_fd);  
    58 }

    测试结果:

    client:

    image

    server:

    image

  • 相关阅读:
    Windows 下 Django/python 开发环境配置
    [Django] Windows 下安装 配置Pinax 工程
    [Django 1.5] Windows + Apache + wsgi配置
    [Django] html 前端页面jQuery、图片等路径加载问题
    [Django] Pinax 项目下APP的 安装与使用
    【代码片段】jQuery测试兄弟元素集合
    【代码片段】jQuery测试后代元素集合
    【代码片段】jQuery测试更多元素集合
    【代码片段】jQuery测试祖先元素集合
    【网页插件】热气球漂浮的效果
  • 原文地址:https://www.cnblogs.com/binchen-china/p/5440802.html
Copyright © 2011-2022 走看看