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

之前看到一篇博文提到程序猿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 = ;
const int BUFFSIZE = ;
const int MAXLINK = ; 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, )) == -)
{
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit();
} memset(&servaddr, , 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)) == -)
{
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
exit();
} if (listen(socket_fd, MAXLINK) == -)
{
exit();
} if ((connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -)
{
exit();
} while()
{
memset(&buff,'\0', sizeof(buff)); recv(connect_fd, buff, BUFFSIZE - , );
send(connect_fd, buff, BUFFSIZE - , ); printf("recv msg from client: %s\n", buff);
}
close(connect_fd);
close(socket_fd);
}

测试结果:

client:

server:

Socket编程回顾,一个最简单服务器程序的更多相关文章

  1. Socket编程实践(3) 多连接服务器实现与简单P2P聊天程序例程

    SO_REUSEADDR选项 在上一篇文章的最后我们贴出了一个简单的C/S通信的例程.在该例程序中,使用"Ctrl+c"结束通信后,服务器是无法立即重启的,如果尝试重启服务器,将被 ...

  2. 使用socket编程实现一个简单的文件服务器

    使用socket编程实现一个简单的文件服务器.客户端程序实现put功能(将一个文件从本地传到文件服务器)和get功能(从文件服务器取一远程文件存为本地文件).客户端和文件服务器不在同一台机器上. pu ...

  3. Python Socket 编程——聊天室演示样例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket ...

  4. socket编程之并发回射服务器

    使用到的函数: // 子进程返回0,父进程返回子进程ID,出错返回-1 pid_t fork(void); pid_t wait(int *wstatus); // 最常用的option是WNOHAN ...

  5. 《用Java写一个通用的服务器程序》01 综述

    最近一两年用C++写了好几个基于TCP通信类型程序,都是写一个小型的服务器,监听请求,解析自定义的协议,处理请求,返回结果.每次写新程序时都把老代码拿来,修改一下协议解析部分和业务处理部分,然后就一个 ...

  6. socket编程之并发回射服务器3

    在socket编程之并发回射服务器一文中,服务器采用多进程的方式实现并发,本文采用多线程的方式实现并发. 多线程相关API: // Compile and link with -pthread int ...

  7. socket编程之并发回射服务器2

    承接上文:socket编程之并发回射服务器 为了让服务器进程的终止一经发生,客户端就能检测到,客户端需要能够同时处理两个描述符:套接字和用户输入. 可以使用select达到这一目的: void str ...

  8. 【并发编程】一个最简单的Java程序有多少线程?

    一个最简单的Java程序有多少线程? 通过下面程序可以计算出当前程序的线程总数. import java.lang.management.ManagementFactory; import java. ...

  9. 《用Java写一个通用的服务器程序》02 监听器

    在一个服务器程序中,监听器的作用类似于公司前台,起引导作用,因此监听器花在每个新连接上的时间应该尽可能短,这样才能保证最快响应. 回到编程本身来说: 1. 监听器最好由单独的线程运行 2. 监听器在接 ...

随机推荐

  1. mac 找文件

    如何找到 etc 方法1: ! D# D! s2 F" f 七度苹果电脑软件1.打开Finder,按快键盘 Command + Shift + G,即可调出 前往文件夹 ,也可以左上角 找到 ...

  2. Net开发环境配置

    Web开发插件: 1.JSEnhancements js和css折叠插件 可以参见dudu的介绍不错的VS2010扩展——JSEnhancements,让js和css也折叠 下载地址:http://v ...

  3. memached 服务器lru算法

    1.LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的.LRU算法的提出,是基于这样一个事实:在前面几条指令中使用频繁的页面很可能在后面的几条 ...

  4. HDU 3255 扫描线(立方体体积并变形)

    Farming Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Su ...

  5. hdu 4638 Group

    http://acm.hdu.edu.cn/showproblem.php?pid=4638 问题其实就是求[L,R]中有多少个连续的段 若每一个人都是一个段 那么[L,R]中每一个朋友关系就会减少一 ...

  6. 二模 (9) day2

    第一题: 题目大意:求满足条件P的N位二进制数的个数.P:该二进制数有至少3个0或者3个1挨在一起.. N<=20000 解题过程: 1.一开始直接写了个dfs把表打了出来,不过没发现什么规律, ...

  7. 服务器端与客户端TCP连接入门(一)

    Java中使用Socket(即套接字)完成TCP程序的开发 服务器端使用ServerSocket接收客户端的连接请求,每一个客户端都使用一个Socket对象表示 在服务器端每次运行时都要使用accep ...

  8. ros与下位机通信常用的c++ boost串口应用

    一.首先移植c++ boost 库: 1. 先去 Boost官网 下载最新的Boost版本, 我下载的是boost_1_6_0版本, 解压. 2. 进入解压后目录: cd boost_1_6_0, 执 ...

  9. Phonebook 导入SD上的.vcf联系人

    2014-01-11 17:29:22 1. 当用户选择Phonebook中从SD卡导入联系人的操作后,程序回调转到ImportVCardActivity,然后用户选择好要导入的.vcf文件,并点击“ ...

  10. WP8 独立存储 总结3(应用设置)

    •可在独立存储中使用ApplicationSettings对象•在独立存储中存储键/值对的Dictionary方式存储 •存储的对象将永久保存 在应用设置中保存数据 void saveString(s ...