linux网络编程(二)----套接字建立网络连接及I/O模型

源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字。其用于标识客户端请求的服务器和服务。
它是网络通信过程中端点的抽象表示,包含进行网络通信必需的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
理解为用于网络编程结构体,设置端口连接 。使用文件描述符操作。

流套接字(SOCK_STREAM):

流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP(The Transmission Control Protocol)协议。

数据报套接字(SOCK_DGRAM):

数据报套接字提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP(User Datagram Protocol)协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。

原始套接字(SOCK_RAW):

原始套接字(SOCKET_RAW)允许对较低层次的协议直接访问,比如IP、 ICMP协议,它常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以自如地控制Windows下的多种协议,能够对网络底层的传输机制进行控制,所以可以应用原始套接字来操纵网络层和传输层应用。比如,我们可以通过RAW SOCKET来接收发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以用来发送一些自定包头或自定协议的IP包。网络监听技术很大程度上依赖于SOCKET_RAW

原始套接字与标准套接字(标准套接字指流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字。

1、创建socket用于接受网络连接请求:
#include <sys/types.h>          
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//domain  地址族,用于说明套接字的具体用途,AF_INET
//type  套接字类型, SOCK_STREAM,SOCK_DGRAM
//protocol  指定协议类型,常用默认0
//返回值:成功,流式套接字的文件描述符;失败,-1

套接字占用文件描述符资源,打开多了就连不上了。

2.1、用于服务器端,绑定IP和端口
#include <sys/types.h>          
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//sockfd   待绑定地址信息的套接字描述符
//sockaddr 待绑定地址结构体的起始地址
//addrlen  待绑定地址结构体大小
//返回值:成功,返回0;失败,返回-1
2.2、用于客户端,建立TCP连接
#include <sys/types.h>    
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//connect       函数通常用于客户端建立tcp连接。
//sockfd:      标识一个套接字。
//serv_addr:   套接字s想要连接的主机地址和端口号。
//addrlen:name 缓冲区的长度。
//返回值:成功则返回0,失败返回-1

connect操作之后代表对应的套接字已连接,UDP协议在创建套接字之后,可以同多个服务器端建立通信,而TCP协议只能与一个服务器端建立通信,TCP不允许目的地址是广播或多播地址,UDP允许。当然UDP协议也可以像TCP协议一样,通过connect来指定对方的ip地址、端口。
struct sockaddr结构类型是用来保存socket信息的:

struct sockaddr 
{
   unsigned short sa_family;//一般为AF_INET,代表Internet(TCP/IP)地址族
   char sa_data[14];       //14 字节的协议地址,包含该socket的IP地址和端口号
};

另外还有一种结构类型:

struct sockaddr_in 
{
   short int sin_family;        // 地址族
   unsigned short int sin_port; // 端口号
   struct in_addr sin_addr;     // IP地址
   unsigned char sin_zero[8];   // 填充0以保持与struct sockaddr同样大小
};
//保存以十六进制表示的IP地址
struct in_addr 
{ 
   unsigned long s_addr;//in_addr_t s_addr
};

3、改变socket状态为监听状态

#include <sys/types.h>         
#include <sys/socket.h>
int listen(int sockfd, int backlog);
//sockfd  待改变状态的套接字描述符
//backlog 等待连接的队列最大单体个数。
//返回值:成功返回0.失败-1

4、接受客户端发送的连接请求

#include <sys/types.h>        
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//sockfd    待监听的套接字描述符
//addr    用于接收客户端的连接地址
//addrlen   客户端地址的长度,在调用accept()之前,必须有长度值,
            调用完成之后传出一个实际长度值
//返回值:成功,返回连接套接字的文件描述符;失败,-1

5、发送数据
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//sockfd 使用sockfd所关联的套接字发送数据
//buf 待发送数据的起始地址
//len 待发送数据的字节长度
//flags 旗标,发送方式
//返回值:实际发送成功的字节数
6、读取数据

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//sockfd  从sockfd所关联的套接字接受数据
//buf    存放接收数据的空间的起始地址
//len    存放空间的最大字节长度
//flags   旗标,接收方式
//返回值:实际发送成功的字节数

记录主机的信息结构体

struct hostent
{
      char *h_name;         //official name of host
      char **h_aliases;     //alias list */主机的别名,以NULL做为结束标记
      int h_addrtype;       //host address type
      int h_length;         //length of address
      char **h_addr_list;   //list of addresses
    //是个字符数组指针,存放二进制地址,表示主机的ip地址,是以网络字节序存储的。
    //不能直接用printf带%s参数来它,需要调用inet_ntop()。
    //指针指向空间,空间内为结构体
}
#define h_addr h_addr_list[0] /* for backward compatibility */

关于ip地址和dots-and-number字符串之间的转换有若干个函数:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
in_addr_t inet_network(const char *cp);
char *inet_ntoa(struct in_addr in);
struct in_addr inet_makeaddr(int net, int host);
in_addr_t inet_lnaof(struct in_addr in);
in_addr_t inet_netof(struct in_addr in);
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
int inet_pton(int af, const char *src, void *dst);  

并发服务器伪代码

多线程版:

建立一次连接,就创建一个线程去处理该连接,主线程永远负责监听套接字的处理。创建线程消耗内存少,创建简单,使用简单

socket
bind
listen
while()
{
    connfd == accept;
    pthread_create(NULL, thread_func,connfd);
}
多进程版:

每建立一次连接,就创建一个进程去处理该连接,父线程永远负责监听套接字的处理。

socket
bind
listen
while()
{
    connfd == accept;
    if((pid = fork()) == 0)
    {
        处理当前连接
    }
}
I/O模型

#######阻塞式I/O
数据到达,从外设或网络到内核(需要等待),从内核读走/复制走。函数只要调一次,但耗时效率低。只能看一个描述符,其他等待,有前后关系时使用。读发线程,收线程
#######非阻塞式I/O
频繁调用,轮询问。
#######信号驱动I/O
信号通知
#######异步I/O
时间上无序无干扰,需要内核支持
#######I/O复用
解决内存开销问题,并发数上线,K10C问题。同时监控多个描述符,机制下决定谁准备好了拿来用,筛选,处理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容