Fork me on GitHub

linux-socket

http://www.cnblogs.com/mingda/archive/2010/11/12/1875465.html

http://www.cnblogs.com/mingda/archive/2010/11/14/1876961.html

http://www.ibm.com/developerworks/cn/aix/library/au-libev/

 

http://blog.csdn.net/hguisu/article/details/7445768/    socket编程,讲的比较清楚,看的比较明白
http://acm.tzc.edu.cn/acmhome/projectList.do?method=projectNewsDetail&nid=2
http://goodcandle.cnblogs.com/archive/2005/12/10/294652.aspx

 

构建现代的服务器应用程序需要以某种方法同时接收数百、数千甚至数万个事件,无论它们是内部请求还是网络连接,都要有效地处理它们的操作。有许多解决方案,但是 libevent 库和 libev 库能够大大提高性能和事件处理能力。

在 Linux 下一切资源皆文件,普通文件是文件,磁盘打印机是文件,socket 当然也是文件。在 Linux 下创建一个新的 socket 连接,实际上就是创建一个新的文件描述符。
因此,我们可以通过使用 ulimit -n 来限制程序所能打开的最大文件描述符数量,从而达到限制 socket 创建的数量。

在阅读这一系列的文章时,我希望大家始终记住以下几点:

1. 软件开发没有银弹,人们总是试图找到问题的唯一解和最优解,但事实是每个问题都有N种解,并且在不同情况下最优解是不一样的,如果非要说软件开发有银弹, 那么这颗银弹就是人的心,是否找能到最优解,在于你是否能把握住了所有事情的平衡点。所以,请不要说某某机制最好、某某算法最优、某某架构万能、不需要再 了解其他了。也请不要自以为目空一切技术,商业和盈利至上,实现途径和方式无所谓。请抱着一切皆有可能的心态看待所有事物,才有更多机会看到平衡点。

2. 语言、平台、API只是迷人眼的东西,它们好像什么都是,其实什么都不是。解决问题的关键在于设计者的心,设计者是否对要解决的问题和问题的上下文了然于 心。不要把学习语言、学习平台、学习API当作目标,它们只是泥沙和工具,最终我们要建造的是房屋,所以请把目标放得更远。也不要把它们当成阻碍,因为它 们生来就是要让人使用的东西,不可能形成阻碍,如果你觉得它们是阻碍,那实际上那个阻碍只在你心里。

3. 记得:Do one thing, and do it well。一次只做一件事,并且做好它。这一系列文章的基本开发和测试环境是Linux,编译器是gcc。如果你之前对Linux不是很熟悉,我建议你安 装一个VMware,并安装Ubuntu桌面系统,然后apt-get install build-essential,这样你的系统里就有完整的开发环境了,gnome自带的gedit很好用,我也是这么做的。不要一上来就Linux命令 行界面加vi编辑器,没必要为难自己也不要搞得自己像黑客一样。请记住,我们当前要做的是高性能socket服务器,只做这一件事,并且做好它!不是研究 Linux命令行或者vi编辑器,那些等有空再慢慢研究还来的及。

4. 师傅请进门修行靠个人。文章和教程的内容其实都是转之由转的东西,如果要了解原汁原味的内容,首选应该去阅读操作系统的代码,其次是系统文档,再次才是网 络教程。而经验是世界上最难传达的东西,文字只能让你形成记忆,不能让你获得经验,它只是像买彩票一样给你提供一个机会,让在你实践过程中可能会有那么一 下的灵光一现,然后得出自己的结论,那才是你的真正经验。如果把生活比喻成RPG,造物主怎么可能让经验可以在玩家之间传递呢?那不是乱了套了,打RPG 我们可以学各种技能,但是要得到经验就得打怪做任务,生活其实也是一样的道理。

 

本章演示了一个简单的echo服务器,它只支持一次处理一个连接,并且在连接退出时,服务器端也跟着关闭。

通过这个简单的例子,我们学习了基本的socket初始化过程和连接的响应方式。

当然这些知识对于我们的远大目标“高性能socket服务器"来说是远远不够的,但是这些是基础的基础,至少我们已经迈开了第一步。

下一章我将向大家介绍如何利用IO重用,在一个进程中同时处理多个连接的请求,敬请期待。

上一章,我向大家演示了一个最基本的socket服务器结构,它一次只能响应一个连接请求,而“能同时响应多个连接和请求”无疑是现实生活中对 socket服务器的最基本要求。要如何让socket服务器可以同时响应多个连接和请求呢?多线和多进程程肯定是大部分人首先想到的,可能很多人不一定 真正清楚多线程和多进程的socket服务器架构具体意味着什么,但是至少大家都或多或少听说过这两种技术。不过本章中,我们暂时还不会涉及到多线程和多 进程的服务器架构,我它们归类为设计范畴,而我们暂时还没有脱离泥水匠身份,所以还要继续学习“泥沙之用途“,设计的事情需要等到我们泥水匠毕业,升级建 筑设计师的时候再说。

那么本章具体的内容是什么呢?真是没有悬念,在上一章中我已经提前透露了:IO重用。下面就正式进入主题吧。

IO重用技术有很多种,有些是夸平台的,有些是平台独有的,这里就列举一些我知道的:
名称    平台
select        Linux, *BSD, Mac OS X, Solaris, Windows
poll        Linux, *BSD, Mac OS X
epoll          Linux
/dev/poll    Solaris
kqueue      FreeBSD
IOCP          Windows
每一种IO重用技术都是通过操作系统提供的一组特定的API函数调用来提供支持的,我们所要学的就是学会怎么用这些API并且了解每种技术背后的原理和来龙去脉。
本章就从最通用应该也是最早出现的IO重用技术select开始。
补充说明一点,IO重用并不局限于用在socket编程上,只要涉及到IO的编程都可以应用。

后续我可能会继续花一到两章来描述poll和epoll,但也可能直接就介绍如何使用夸平台的libev和libevent库。特别是poll实际 上它对select来说没有改进的地方,属于同一水平,实际上它们只是起源不一样,但是时代差不多所以水平也就差不多,而后续的epoll、 dev/poll、iocp则是百家争鸣时期各个操作系统平台为了进一步提高io重用效率而设计的新机制,它们才本质上对select和poll等老模式 进行了改进,所以我可能会跳过poll介绍epoll。

libev的实验代码我其实已经做好了,poll和epoll有点懒得重复了,具体怎么样还不确定就留个悬念吧,呵呵。

libev是libevent之后的一个事件驱动的编程框架,其接口和libevent基本类似。据官方介绍,其性能比libevent还要高,bug比libevent还少。

以下软件使用了libev作为其事件库,可见libev也足够稳定作为生产使用。
  • GNU Virtual Private Ethernet
  • rxvt-unicode
  • auditd
  • the Deliantra MORPG Server and Client

libevent

Chromium、Memcached、NTP、HTTPSQS等著名的开源程序都使用libevent库

 

/* 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<netinet/in.h>
#define DEFAULT_PORT 8000
#define MAXLINE 4096
int main(int argc, char** argv)
{
int    socket_fd, connect_fd;
struct sockaddr_in     servaddr;
char    buff[4096];
int     n;
//初始化Socket
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);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。
servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为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, 10) == -1){
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
printf("======waiting for client's request======\n");
while(1){
//阻塞直到有客户端连接,不然多浪费CPU资源。
if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
//接受客户端传过来的数据
n = recv(connect_fd, buff, MAXLINE, 0);
//向客户端发送回应数据
if(!fork()){ /*紫禁城*/
if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1)
perror("send error");
close(connect_fd);
exit(0);
}
buff[n] = '\0';
printf("recv msg from client: %s\n", buff);
close(connect_fd);
}
close(socket_fd);
}

 

posted on 2014-08-31 19:37  阳光-源泉  阅读(316)  评论(0编辑  收藏  举报

导航