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); 创建一个套接字,并且设置该套接字协议类型。

int bind(SOCKET socket, const struct sockaddr* address, socklen_t address_len); 为套接字绑定IP和端口。

int listen(int socket, int backlog); listen通过socket套接字和该套接字绑定的IP信息在内核开启监听,并且返回监听描述符。 此处监听工作交给内核处理,代码本身不阻塞,但内核对应端口一直在做监听工作。同时维护两个连接队列,大小由backlog决定。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 发送连接请求,代码默认阻塞。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 接受连接请求,代码默认阻塞。 accept实际上是在从内核listen维护的就绪队列中取描述符。

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

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

Client请求时间是不确定的,当多个请求到Server时,处于请求队列,等待listen的端口逐个处理至就绪队列。 connect处于阻塞态等待请求从listen的就绪队列被accept调度返回具体用于数据传输的accept_fd描述符。 accept处于阻塞态,当请求队列为空或处理完毕时。

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

下面附上整个流程代码。

/* File Name: server.c */
#include<stdio.h> 
#include<stdlib.h>  
#include<string.h>  
#include<errno.h>  
#include<sys/types.h>  
#include<sys/socket.h>  
#include<sys/unistd.h>
#include<netinet/in.h>  
const int DEFAULT_PORT = 2500;  
const int BUFFSIZE = 1024;
const int MAXLINK = 10;

int main(int argc, char** argv)  
{  
    int    socket_fd, connect_fd;  
    struct sockaddr_in servaddr;  
    char buff[BUFFSIZE];    
    
    if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {  
        printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);  
        exit(0);  
    } 
    
    memset(&servaddr, 0, sizeof(servaddr));  
    servaddr.sin_family = AF_INET;  
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(DEFAULT_PORT);
  
    if (bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
    {  
        printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);  
        exit(0);  
    }  
    
    if (listen(socket_fd, MAXLINK) == -1)
    {  
        exit(0);  
    }   

    if ((connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1)
    {  
        exit(0);  
    } 
    
    while(1)
    {   
        memset(&buff,'\0', sizeof(buff));  
        
        recv(connect_fd, buff, BUFFSIZE - 1, 0);  
        send(connect_fd, buff, BUFFSIZE - 1, 0); 
        
        printf("recv msg from client: %s\n", buff);  
    }  
    close(connect_fd);    
    close(socket_fd);  
}
 

测试结果: client:

server:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Kurt Niu 的博客

[开源]使用C# 对CPU卡基本操作封装

Github 地址:https://github.com/zifeiniu/CPUCardLib

1782
来自专栏码洞

你没读过的Jetty使用入门

在近几年的开源Java容器市场上,Tomcat依旧保持在龙头老大的位置,其地位丝毫没有被撼动的迹象。与此同时Tomcat也因为架构臃肿结构复杂而饱受批评。作为T...

1462
来自专栏FreeBuf

经验分享 | Burpsuite抓取非HTTP流量

使用Burp对安卓应用进行渗透测试的过程中,有时候会遇到某些流量无法拦截的情况,这些流量可能不是HTTP协议的,或者是“比较特殊”的HTTP协议(以下统称非HT...

97510
来自专栏散尽浮华

Linux系统下的ssh使用(依据个人经验总结)

对于linux运维工作者而言,使用ssh远程远程服务器是再熟悉不过的了!对于ssh的一些严格设置也关系到服务器的安全维护,今天在此,就本人工作中使用ssh的经验...

7497
来自专栏腾讯移动品质中心TMQ的专栏

像 google 一样测试系列之六: 实战篇

本文主要介绍 google 一样测试系列的实战内容,Mock 和反射执行,会穿插在各章节中,因此不单独成节了。

1661
来自专栏Seebug漏洞平台

Struts2 REST 插件 XStream 远程代码执行漏洞 S2-052(CVE-2017-9805)

漏 洞 概 述 1. 漏洞信息: 2017年9月5日,Apache Struts 发布最新安全公告。Apache Struts2 的 REST 插件存在远程...

2986
来自专栏zhangdd.com

windows系统Tomcat启动过程中找不到JAVA_HOME解决方法

在winserver上明明已经安装了JDK1.6并设置好了JAVA_HOME,可偏偏Tomcat在启动过程中找不到。

861
来自专栏黑白安全

php漏洞与代码审计

在甲方公司做代码审计一般还是以白盒为主,漏洞无非这么几类,XSS、sql注入、命令执行、上传漏洞、本地包含、远程包含、权限绕过、信息泄露等。

1375
来自专栏黑泽君的专栏

day07_Tomcat服务器与http学习笔记

    WEB,在英语中web即表示网页的意思,它用于表示Internet主机上(服务器)供外界访问的资源。

1201
来自专栏皮振伟的专栏

[linux][memory]进程的最大内存使用量的讨论

前言: 一个进程最大能使用多少虚拟内存,能控制的地方还是比想象的多一点。 尤其是IaaS上,一个qemu进程能使用多少虚拟内存,就是对应着虚拟机的物理内存的最大...

2.3K11

扫码关注云+社区

领取腾讯云代金券