UNIX网络编程-基本API介绍(一)

1、基本结构

大多数套接口函数都需要一个指向套接口地址结构的指针作为参数。每个协议族都定义它自己的套接口地址结构。这些结构的名字均以“sockaddr_”开头,并以对应每个协议族的唯一后缀结束。

1.1 IPv4套接口地址结构

也称为“网际套接口地址结构”,以“sockaddr_in”命名,在头文件<netinet/in.h>中。

struct in_addr
{
    in_addr_t s_addr;   //32为IP地址
};

struct sockaddr_in
{
    uint8    sin_len; //为了增加OSI协议支持,有些版本是没有这个字段的,一般不用
    sa_family_t sin_family;//类型为u_short,IPv4版本的值为AF_INET
    in_port_t sin_port;//16位整数

    struct in_addr sin_addr;//地址结构,可以为32位整数,有些版本运行访问每个字节
    char sin_zero[8]; //暂时无用
};

注意:

一般情况下,以上结构中只使用sin_family、sin_addr、sin_port三个成员,几乎所有版本实现都会增加sin_zero字段,所以所有套接口地址结构都至少为16字节。

IPv4地址和TCP或UDP端口号在套接口地址结构中总是以网络字节序来存储。

可以有两种不同方法来访问IPv4地址,假设serv为一个网际套接口地址,那么可以用serv.sin_addr(一个in_addr结构)和serv.sin_addr.s_addr(一个32位整数)两种形式来访问IPv4地址。现在大多数情况下使用32位整数的形式来访问。

1.2 通用套接口地址结构

当以参数形式传递给套接口函数时,套接口结构总是通过指针来传递,这样就会有一个问题,如何来声明所传指针的数据类型?这样通用套接口就派上用场了。

其实用void *类型很容易就解决这个问题了,但套接口函数在标准C之前定义的,当时采用了如下结构:(在头文件sys/socket.h中)

struct sockaddr
{
    uint8_t sa_len;
    sa_family_t sa_family; //AF_xxx
    char sa_data[14];
};

例如,bind函数的原型为:

int bind(int , struct sockaddr *, socklen_t );

这样就要求使用的时候需要将套接口结构指针强转成该类型。

1.3 IPv6套接口地址结构

在头文件netinet/in.h中定义。

struct in6_addr
{
    unit8_t s6_addr[16]; //128位地址
};

#define SIN6_LEN

struct sockaddr_in6
{
    uint8_t sin6_len;
    sa_family_t sin6_family;
    in_port_t sin6_port;

    uint32_t sin6_flowinfo;
    struct in6_addr sin6_addr;
};

注意:

如果系统支持长度成员,则SIN6_LEN常量必须定义。

IPv6地址族是AF_INET6

sin6_flowinfo成员分为三个字段:

低24位是流量标号;

下4位是优先级;

再下4位保留;

1.4 值-结果参数

当把套接口地址结构传递给套接口函数时,总是通过指针来传递的。现在结构的长度也作为参数传递,其传递的方式取决于结构传递方向:从进程到内核与从内核到进程。从进程到内核传递整数长度,从内核到进程传递整型指针。

从进程到内核传递套接口结构的有三个函数:bind、connect、sendto。由于指针和指针所指向结构的大小都传递给内核,所以从进程到内核需要拷贝多少数据是已知的。

从内核到进程有四个函数:accept、recvfrom、getsockname、getpeername。传长度是传递指向整数的指针。

为什么要传指针呢?因为:当函数被调用时,结构大小是一个值(告诉内核该结构的大小,使内核在写此结构时不越界),当函数返回时,结构大小又是一个结果(它告诉进程,内核在此结构中确切存储了多少信息),这种参数类型叫值-结果参数。

其他值-结果参数:

select函数中间的三个变量;

getsockopt函数的长度变量;

使用函数recvmsg时,msghdr结构中的两个成员:msg_namelen和msg_controllen;

ifconf结构中的成员ifc_len;

sysctl函数的前两个长度参数。

2、基本接口

2.1 如何判断系统大小端

int main(int argc, char *argv[])
{
    uinon
    {
        short s;
        char c[sizeof(short)];
    } un;
    un.s = 0x0102;
    printf("this os is: ");
    if (sizeof(short) == 2)
    {
        if (un.c[0] == 1 && un.c[1] == 2)
            printf("big-endian\n");
        else if (un.c[0] == 2 && un.c[1] == 1)
            printf("little-endian\n");
        else
            printf("unknown\n");
    }
    else
    {
        printf("sizeof(short) = %d\n", sizeof(short));
    }

    return 0;
}

2.2 各种系统函数介绍

2.2.1 htons和htonl,用于将主机字节序转化为网络字节序

-----------------------------------------------------------------

#include <netinet/in.h>

uint16_t htons(uint16_t host16bitvalue);//返回网络字节序值

uint32_t htonl(uint32_t host32bitvalue);//返回网络字节序值

------------------------------------------------------------------

传入16或32为主机字节序值,返回相应的网络字节序值。

2.2.2 ntohs和ntohl,用于将网络字节序转化为主机字节序

------------------------------------------------------------------

#include <netinet/in.h>

uint16_t ntohs(uint16_t net16bitvalue);//返回主机字节序值

uint32_t ntohl(uint32_t net32bitvalue);//返回主机字节序值

------------------------------------------------------------------

传入16或32为网络字节序值,返回相应的网络字节序值。

2.2.3 bzero、bcopy、bcmp,相当于C语言中的memset、memcpy、memcmp

------------------------------------------------------------------

#include <strings.h>

void bzero(void *dest, size_t nbytes);

void bcopy(const void *src, void *dest, size_t nbytes);

int bcmp(const void *ptr1, const void *prt2, size_t nbytes); //返回0相等,非0不等

------------------------------------------------------------------

------------------------------------------------------------------

#include <string.h>

void *memset(void *dest, int c, size_t len);

void *memcpy(void *dest, const void *src, size_t nbytes);

int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);//返回0相等,非0不等

------------------------------------------------------------------

2.2.4 inet_aton,将一个字符串IP地址转换为一个32位的网络字节序地址。

------------------------------------------------------------------

#include <arpa/inet.h>

int inet_aton(const char *strptr, struct in_addr *addrptr);//返回1有效,返回0无效

------------------------------------------------------------------

参数strptr为点分式IP字符串,addrptr为转化后的in_addr格式地址。

2.2.5 inet_addr,将一个点分式IP转化为一个32位整数

------------------------------------------------------------------

#include <arpa/inet.h>

in_addr_t inet_addr(const char *strptr);//返回32位整数,若地址非法,返回INADDR_NONE

------------------------------------------------------------------

参数strptr为点分式IP字符串。

INADDR_NONE等于255.255.255.255(IPv4的有限广播地址),所以该函数不能处理此地址。尽量使用inet_aton,不使用inet_addr。

2.2.6 inet_ntoa,将一个32位网络字节序地址转换为一个字符串IP地址。

------------------------------------------------------------------

#include <arpa/inet.h>

char *inet_ntoa(struct in_addr inaddr);//返回点分式IP字符串

------------------------------------------------------------------

传入一个32位网络字节序地址。

inet_ntoa函数的执行结果放在静态内存中,是不可重入的。

2.2.7 inet_pton,转换字符串到网络地址

------------------------------------------------------------------

#include <arpa/inet.h>

int inet_pton(int family, const char *strptr, void *addrptr);

返回:1 成功,0 输入格式不对,-1 失败。

------------------------------------------------------------------

family表示地址族,strptr为源地址字符串,addrptr为转换后的网络地址。

若参数family不被支持,则出错,errno置为EAFNOSUPPORT。

2.2.8 inet_ntop,转换网络地址到字符串

------------------------------------------------------------------

#include <arpa/inet.h>

const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

返回:指向结果的指针 成功;NULL 失败。

------------------------------------------------------------------

family表示地址族,addrptr是传入的网络地址,strptr存放转换后的结果,len防止缓存区溢出,如果缓存区大小不够,则返回NULL,并将errno置为ENOSPC。

若参数family不被支持,则出错,errno置为EAFNOSUPPORT。

2.2.9 readn、writen、readline函数

以上三个函数都在头文件"unp.h"中,下面是这三个函数的具体实现:

------------------------------------------------------------------

readn函数:从一个描述字读取n字节。[lib/readn.c]

ssize_t readn(int fd, void *vptr, size_t n)
{
    ssize_t nleft = n;
    ssize_t nread = 0;
    char *ptr = vptr;

    while (nleft > 0)
    {
        if ((nread = read(fd, ptr, nleft)) < 0)
        {
            if (errno == EINTR)
                nread = 0; //call read() again
            else
                return -1;
        }
        else if (nread == 0)
        {
            break;
        }

        nleft -= nread;
        ptr += nread;
    }

    return (n-nleft);
}

------------------------------------------------------------------

------------------------------------------------------------------

write函数:往一个描述子写n个字节[lib/writen.c]

ssize_t writen(int fd, const void *vptr, size_t n)
{
    ssize_t nleft = n;
    ssize_t nwritten = 0;
    const char *ptr = vptr;

    while (nleft > 0)
    {
        if ((nwritten = write(fd, ptr, nleft)) <= 0)
        {
            if (errno == EINTR)
            {
                nwritten = 0; //call write() again
            }
            else
            {
                return -1;
            }
        }

        nleft -= nwritten;
        ptr += nwritten;
    }

    return n;
}

------------------------------------------------------------------

------------------------------------------------------------------

readline函数:从一个描述字读取一样文本,一次读一个字节。

ssize_t readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t n = 0;
    ssize_t rc = 0;
    char c;
    char *ptr = vptr;

    for (n = 1; n<maxlen; ++n)
    {
        again:
        if ((rc = read(fd, &c, 1)) == 1)
        {
            *ptr++ = c;
            if (c == ‘\n‘)
                break;
        }
        else if (rc == 0)
        {
            if (n == 1)
                return 0; //no data read
            else
                break; //some data was read
        }
        else
        {
            if (errno == EINTR)
                goto again;
            return -1;
        }
    }
    *ptr = 0;

    return n;
}

------------------------------------------------------------------

注意:EINTR是linux函数的返回状态,在不同的函数中意义不同,如下:

write,表示由于信号中断,没有写成功数据。

read,表示由于信号中断,没读成功数据。

sem_wait,函数调用被信号处理函数中断。

recv,由于信号中断返回,没有任何数据可用。

2.2.10 isfdtype,测试描述符类型

------------------------------------------------------------------

#include <sys/stat.h>

int isfdtype(int fd, int fdtype);

返回:1 是指定类型;0 不是指定类型;-1 出错。

------------------------------------------------------------------

要测试是否为套接口描述子,fdtype应设为S_IFSOCK。

2.2.11 socket,用来获取一个文件描述符

------------------------------------------------------------------

#include <sys/socket.h>

int socket(int family, int type, int protocol);

返回:非负 成功;-1 失败。

------------------------------------------------------------------

family是协议族,有五种取值:

AF_INET    IPv4协议

AF_INET6   IPv6协议

AF_LOCAL   Unix域协议

AF_FOUTE   路由套接口

AF_KEY     秘钥套接口

一般前两种使用较多。

type指定套接口类型,有三种:

SOCK_STREAM字节流套接口

SOCK_DGRAM数据报套接口

SOCK_RAW原始套接口

protocol在type不是原始套接口的情况下一般设为0。(原始套接口之后详细介绍)

注意:不是所有的family和type组合都是有效的。

2.2.12 connect,连接

当用socket建立了套接口后,可以调用connect为这个套接字指明远程端的地址。分两种情况:字节流套接口,connect使用三次握手建立一个连接;数据报套接口,connect仅指明远程端地址,不向它发送任何数据。

------------------------------------------------------------------

#include <sys.socket.h>

int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);

返回:0 成功;-1 失败。

------------------------------------------------------------------

在调用connect之前不必非得调用bind函数。

如果是TCP,则connect激发TCP的三路握手过程,在阻塞情况下,只有在连接建立成功或出错时该函数才返回。(三次握手协议之后介绍)

出错情况:

没有收到SYN分节的响应,在规定时间内经过重发仍无效,则返回ETIMEDOUT;

如果对SYN分节的响应是RST,表示服务器在指定端口上没有相应的服务,返回ECONNREFUSED;

如果发出 SYN在中间路由器上引发一个目的地不可达ICMP错误,在规定时间内经过重发仍无效,则返回EHOSTUNREACH或ENETUNREACH错误。

注意:

如果connect失败,则套接口将不能再使用,必须关闭,不能对此套接口再调用函数connect。

2.2.13 bind,为套接口分配一个本地IP和协议端口

对于网际协议,协议地址是32位IPv4地址或128位IPv6地址与16位的TCP或UDP端口号的组合。如指定端口为0,调用bind时内核将选择一个临时端口,如果指定一个通配IP地址,则要等到建立连接后内核才选择一个本地IP地址。

------------------------------------------------------------------

#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

返回:0 成功;-1 失败。

------------------------------------------------------------------

对于IPv4,通配地址是INADDR_ANY,其值一般为0。使用方法如下:

struct sockaddr_in servaddr;

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

对于IPv6,方法如下:

struct sockaddr_in6 serv;

serv.sin6_addr = in6addr_any; (系统分配变量in6addr_any并将其初始化为常值IN6ADDR_ANY_INIT。)

注意:

如果让内核选择临时端口,bind并不返回所选的端口值,要得到一个端口,必须使用getsockname函数;

bind失败的常见错误是EADDRINUSE(地址已使用)。

2.2.14 listen,监听

listen函数仅被TCP服务器调用,它的作用是将用sock创建的主动套接口转换成被动套接口,并等待来自客户端的连接请求。

------------------------------------------------------------------

#include <sys/socket.h>

int listen(int sockfd, int backlog);

返回:0 成功;-1 失败。

------------------------------------------------------------------

第一个参数是socket函数返回的套接口描述字;第二个参数规定了内核为此套接口排队的最大连接个数。由于listen函数第二个参数的原因,内核要维护两个队列:已完成连接队列和未完成连接队列。未完成队列中存放的是TCP连接的三路握手未完成的连接,accept函数是从已连接队列中取连接返回给进程;当以连接队列为空时,进程将进入睡眠状态。

参数backlog曾经规定为监听套接口上的未完成连接队列和已完成连接队列总和的最大值,但各个系统的定义方法都不尽相同;历史上常把backlog置为5,但对于繁忙的服务器是不够的;backlog的设置没有一个通用的方法,依情况而定,但不要设为0。

2.2.15 accept,接收

accept函数由TCP服务器调用,从已完成连接队列头返回一个已完成连接,如果完成连接队列为空,则进程进入睡眠状态。

------------------------------------------------------------------

#include <sys/socket.h>

int accept(int sockfd, const struct sockaddr *cliaddr, socklen_t *addrlen);

返回:非负描述符 成功;-1 出错。

------------------------------------------------------------------

第一个参数是socket函数返回的套接口描述字;第二个和第三个参数分别是一个指向连接方的套接口地址结构和该地址结构的长度;该函数返回的是一个全新的套接口描述字;如果对客户段的信息不感兴趣,可以将第二和第三个参数置为NULL。

2.2.16 read和write,文件读写

当服务器和客户端的连接建立起来后,就可以进行数据传输了,服务器和客户端用各自的套接字描述符进行读/写操作。因为套接字描述符也是一种文件描述符,所以可以用文件读/写函数write()和read()进行接收和发送操作。

------------------------------------------------------------------

read:从文件描述符读。

#include <unistd.h>

int read(int sockfd, char *buf, int len);

返回:非负 成功;-1 失败。

------------------------------------------------------------------

------------------------------------------------------------------

write:写入文件描述符。

#include <unistd.h>

int write(int sockfd, char *buf, int len);

返回:非负 成功;-1 失败。

------------------------------------------------------------------

2.2.17 send和recv,发送和接收

TCP套接字提供了send()和recv()函数,用来发送和接收操作。这两个函数与write()和read()函数很相似,只是多了一个附加的参数。

------------------------------------------------------------------

send:发送数据。

#include <sys/types.h>

#include <sys/socket.h>

ssize_t send(int sockfd, void *buf, size_t size, int flags);

返回:发送的字节数 成功;-1 失败。

------------------------------------------------------------------

------------------------------------------------------------------

recv:接收数据。

#include <sys/types.h>

#include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t size, int flags);

返回:接收的字节数 成功;-1 失败。

------------------------------------------------------------------

注意:

以上两个函数中flags参数为传输控制标记。(还不甚明白)

这里并没有sendto和recvfrom接口的介绍,之后会做两组接口的比较,就不在这里写了。

2.2.18 close,关闭套接口

------------------------------------------------------------------

#include <unistd.h>

int close(int sockfd);

返回:0 成功;-1 失败。

------------------------------------------------------------------

TCP套接口的close缺省功能是将套接口做上“已关闭”标记,并立即返回到进程。这个套接口描述字不能再为进程使用,但TCP将试着发送已排队待发的任何数据,然后按正常的TCP连接终止序列进行操作。

close把描述字的访问计数减1,当访问计数仍大于0时,close并不会引发TCP的四分组连接终止序列。若确实要发一个FIN,可以用函数shutdown。

3、简单的服务端、客户端例程

3.1 服务端代码

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
    int sockListen, sockConn;
    struct sockaddr_in serverAddr;
    struct sockaddr_in clientAddr;

    int sin_size, port;

    char hello[] = "Hello, world!\n";

    if (argc != 2)
    {
        printf("parameter num err!\n");
        return 0;
    }

    if ((port = atoi(argv[1])) < 0)
    {
        printf("the parameter should be a integer!\n");
        return 0;
    }

    printf("port = %d\n", port);

    if ((sockListen = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("create sockListen err!\n");
        return 0;
    }

    bzero(&serverAddr, sizeof(struct sockaddr_in));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(port);

    if (bind(sockListen, (struct sockaddr *)(&serverAddr), sizeof(struct sockaddr_in)) == -1)
    {
        printf("bind err!\n");
        return 0;
    }

    if (listen(sockListen, 5) == -1)
    {
        printf("listen err!\n");
        return 0;
    }

    while (1)
    {
        if ((sockConn = accept(sockListen, NULL, NULL)) == -1)
        {
            printf("accept err!\n");
            return 0;
        }
        printf("sockConn = %d\n", sockConn);

        if (write(sockConn, hello, strlen(hello)) == -1)
        {
            printf("write err!\n");
            return 0;
        }

        close(sockConn);
    }

    close(sockListen);

    return 0;
}

3.2 客户端代码

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
    int sockConn;
    int port;
    char hello[512];
    struct sockaddr_in serverAddr;

    if (argc != 3)
    {
        printf("parameter num err!\n");
        return 0;
    }

    if ((port = atoi(argv[2])) < 0)
    {
        printf("the parameter should be a integer!\n");
        return 0;
    }

    if ((sockConn = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("create socket err!\n");
        return 0;
    }

    bzero(&serverAddr, sizeof(struct sockaddr_in));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);

    if (inet_aton(argv[1], &serverAddr.sin_addr) == 0)
    {
        printf("addr err!\n");
    return 0;
    }

    if ((connect(sockConn, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr_in))) == -1)
    {
        printf("connect err!\n");
        return 0;
    }

    bzero(hello, sizeof(hello));
    read(sockConn, hello, sizeof(hello));
    printf("%s\n", hello);

    close(sockConn);

    return 0;
}

3.3 运行截图

服务端截图:

客户端截图:

程序说明:本程序只是简单的描述了服务端和客户端的基本工作过程,演示一下api的使用方法,在编码规范上还存在很多不足,比如错误处理全都是简单的输出、许多地方直接使用数字等等。

4、参考资料

http://www.cnblogs.com/riky/archive/2006/11/24/570713.aspx

http://blog.csdn.net/xiong_yao/article/details/8364633

UNIX网络编程-基本API介绍(一)

时间: 2024-10-26 19:12:31

UNIX网络编程-基本API介绍(一)的相关文章

UNIX网络编程-基本API介绍(二)

参考链接:http://www.cnblogs.com/riky/archive/2006/11/24/570713.aspx 1.getsockname和getpeername getsockname函数获取与套接口关联的本地协议地址. getpeername函数获取与套接口关联的远程协议地址. ---------------------------------------------------------------------- #include <sys/socket.h> int 

Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍

写在开头: 在上一节中我们学习了一些基础的用来支持网络编程的API,包括"套接字的地址结构"."字节排序函数"等.这些API几乎是所有的网络编程中都会使用的一些,对于我们正确的编写网络程序有很大的作用.在本节中我们会介绍编写一个基于TCP的套接字程序需要的一些API,同时会介绍一个完整的TCP客户服务器程序,虽然这个程序功能相对简单,但确包含了一个客户服务器程序所有的步骤,一些复杂的程序也都是在此基础上进行扩充.在后面随着学习的深入,我们会给这个程序添加功能. 下面

UNIX网络编程 卷1:套接字联网API

这篇是计算机类的优质预售推荐>>>><UNIX网络编程 卷1:套接字联网API> UNIX和网络专家W. Richard Stevens的传世之作,世界著名网络专家Bill Fenner和Andrew M. Rudoff执笔新版 编辑推荐 这是一部传世之作!顶级网络编程专家Bill Fenner和Andrew M. Rudoff应邀执笔,对W. Richard Stevens的经典作品进行修订.书中吸纳了近几年网络技术的发展,增添了IPv6.SCTP协议和密钥管理套接字

Unix网络编程--卷一:套接字联网API 读书笔记

UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 1.简介 2.传输层:TCP.UDP和SCTP 3.套接字编程简介 4.基本TCP套接字编程 5.TCP客户/服务器程序例子 6.I/O复用:select和poll函数 7.套接字选项 8.基本UDP套接字编程 9.基本SCTP套接字编程 10.SCTP客户/服务器程序例子 11.名字与地址转换 12.IPV4与IPV6互操作性 13.守护进程和

[转载] 读《UNIX网络编程 卷1:套接字联网API》

原文: http://cstdlib.com/tech/2014/10/09/read-unix-network-programming-1/ 文章写的很清楚, 适合初学者 最近看了<UNIX网络编程 卷1:套接字联网API>, 英文名叫Unix Network Programming啦,后来上网查了查, 一般都叫UNP逼格会高一点, 就像APUE一样. 他们的作者都是W. Richard Stevens. 另外,他也是TCP/IP Illustrated的作者. 靠,看完作者简介,简直崇拜得

UNIX网络编程 卷2:进程间通信

这篇是计算机类的优质预售推荐>>>><UNIX网络编程 卷2:进程间通信(第2版)> UNIX和网络专家W. Richard Stevens的传世之作 编辑推荐 两卷本的<UNIX网络编程>是已故著名技术作家W. Richard Stevens的传世之作.卷2着重讨论怎样让应用程序与在其它机器上的应用程序进行对话. 良好的进程间通信(IPC)机制是提高UNIX程序性能的关键. 本书全面深入地解说了各种进程间通信形式,包括消息传递.同步.共享内存及远程过程调用

UNIX网络编程入门——TCP客户/服务器程序详解

前言 最近刚开始看APUE和UNP来学习socket套接字编程,因为网络这方面我还没接触过,要等到下学期才上计算机网络这门课,所以我就找了本教材啃了一两天,也算是入了个门. 至于APUE和UNP这两本书,书是好书,网上也说这书是给进入unix网络编程领域初学者的圣经,这个不可置否,但这个初学者,我认为指的是接受过完整计算机本科教育的研究生初学者,需要具有完整计算机系统,体系结构,网络基础知识.基础没打好就上来啃书反而会适得其反,不过对于我来说也没什么关系,因为基础课也都上得差不多了,而且如果书读

UNIX网络编程卷1 回射客户程序 TCP客户程序设计范式

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 下面我会介绍同一个使用 TCP 协议的客户端程序的几个不同版本,分别是停等版本.select 加阻塞式 I/O 版本. 非阻塞式 I/O 版本.fork 版本.线程化版本.它们都由同一个 main 函数调用来实现同一个功能,即回射程序客户端. 它从标准输入读入一行文本,写到服务器上,读取服务器对该行的回射,并把回射行写到标准输出上. 其中,非阻塞式 I/O 版本是所有版本中执行速度最快的,

Unix网络编程中的五种I/O模型_转

转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描述符.接受数据缓冲地址.大小传递给内核,但是如果此时 该与该套接口相应的缓冲区没有数据,这个时候就recvfrom就会卡(阻塞)在这里,知道数据到来的时候,再把数据拷贝到应用层,也就是传进来的地址空 间,如果没有数据到来,就会使该函数阻塞在那里,这就叫做阻塞I/O模型,如下图: 2. 非阻塞I/O模