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

  • 相关阅读:
    Android Gradle Plugin指南(五)——Build Variants(构建变种版本号)
    文件内容操作篇clearerr fclose fdopen feof fflush fgetc fgets fileno fopen fputc fputs fread freopen fseek ftell fwrite getc getchar gets
    文件操作篇 close creat dup dup2 fcntl flock fsync lseek mkstemp open read sync write
    嵌入式linux应用程序调试方法
    version control system:git/hg/subversion/cvs/clearcase/vss。software configruation management。代码集成CI:Cruisecontrol/hudson/buildbot
    最值得你所关注的10个C语言开源项目
    如何记录linux终端下的操作日志
    CentOS 5.5 虚拟机安装 VirtualBox 客户端增强功能
    sizeof, strlen区别
    C/C++嵌入式开发面试题
  • 原文地址:https://www.cnblogs.com/binchen-china/p/5440802.html
Copyright © 2011-2022 走看看