UNIX环境高级编程——TCP/IP网络编程

时间:2023-02-08 21:18:13
常用网络信息检索函数
gethostname()
getpeername()
getsockname()
gethostbyname()
gethostbyaddr()
getprotobyname()
getprotobynumber()
getservbyname()
getservbyport()
网络属性设置
头文件: #include <sys/types.h>    #include <sys/socket.h> 
获取一个套接口选项 int getsockopt(             int sockfd,             int level,     //选项定义的层次。支持的层次仅有SOL_SOCKET和IPPROTO_TCP和IPPROTO_IP             int optname,     //需获取的套接口选项。             void *optval,     //指针,指向存放所获得选项值的缓冲区。             socklen_t *optlen //指针,指向optval缓冲区的长度值。             ); 
返回值:   无错:返回0。出错:返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。 注释:   getsockopt()函数用于获取任意类型、任意状态套接口的选项当前值,并把结果存入optval。在不同协议层上存在选项,但往往是在最高的“套接口”层次上,设置选项影响套接口的操作,诸如操作的阻塞与否、包的选径方式、带外数据的传送等。被选中选项的值放在optval缓冲区中。optlen所指向的整形数在初始时包含缓冲区的长度,在调用返回时被置为实际值的长度。对SO_LINGER选项而言,相当于linger结构的大小,对其他选项来说,是一个整形数的大小。如果未进行setsockopt()调用,则getsockopt()返回系统缺省值。
设置套接口的选项int setsockopt(            int sockfd,     //标识一个套接口的描述字。            int level,     //选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。            int optname,    //需设置的选项。            const void *optval,     //指向存放选项值的缓冲区的指针。            socklen_t optlen    //optval缓冲区长度。            );
返回值:无错:返回0。出错:返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。
注释:setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。有两种套接口的选项:一种是布尔型选项,允许或禁止一种特性;另一种是整形或结构选项。允许一个布尔型选项,则将optval指向非零整形数;禁止一个选项optval指向一个等于零的整形数。对于布尔型选项,optlen应等于sizeof(int);对其他选项,optval指向包含所需选项的整形数或结构,而optlen则为整形数或结构的长度。SO_LINGER选项用于控制下述情况的行动:套接口上有排队的待发送数据,且closesocket()调用已执行。UNIX环境高级编程——TCP/IP网络编程
UNIX环境高级编程——TCP/IP网络编程
UNIX环境高级编程——TCP/IP网络编程

系统IO与服务器模型
在unix/linux下主要有四种I/O模型
  • 阻塞I/O:(管道大小64K)
简单,效率低,最常用读阻塞read,readv,recv,recvfrom,recvmsg缓冲区没可读数据写阻塞write,writev,send,sendmag写缓冲区小于小于要写入数据的量(UDP例外,无缓冲区概念)其他:accept,connect
  • 非阻塞I/O:
可防止进程阻塞在I/O操作上若请求的I/O不能马上完成,返回错误。设置非阻塞需要用循环测试文件描述符是否有数据。(poling)比较耗费CPU资源。实现:(使用fcntl( )函数)#include <unistd.h>#include <fcntl.h>
int fcntl( int fd,    //文件描述符                int cmd,    //操作的命令                long arg    //flock 结构指针
返回值 :成功则返回0,错误则返回-1,并设置errno.例:UNIX环境高级编程——TCP/IP网络编程struct flcok   {   short int l_type;   short int l_whence;   off_t l_start;   off_t l_len;   pid_t l_pid;   }l_type 有三种状态:   F_RDLCK 建立一个供读取用的锁定   F_WRLCK 建立一个供写入用的锁定   F_UNLCK 删除之前建立的锁定   l_whence 也有三种方式:   SEEK_SET 以文件开头为锁定的起始位置。   SEEK_CUR 以目前文件读写位置为锁定的起始位置   SEEK_END 以文件结尾为锁定的起始位置。 
  • I/O多路复用:
允许同时控制多个I/O
思想:
  • 构造一张有关文件描述符的表;
  • 调用一个函数,得到这些描述符中的一个已准备好进行I/O时返回;
  • 返回时,告诉进程的哪个描述符已经准备好,并可以进行I/O.

  • 信号驱动I/O:
异步通信模型

I/O多路复用并发服务器流程
UNIX环境高级编程——TCP/IP网络编程

#include <sys/time.h>#include <sys/types.h>int select ( int n,    //所有监控的文件描述符的集合                  fd_set *readfds,// 所有要读的文件描述符的集合                  fd_set *writefds,//所有要写的文件描述符的集合                  fd_set *exceptfds,//其他要向我们通知的文件描述符                  struct timeval *timeout )//超时设置。timeout可选参数:NULL:一直阻塞,直到文件描述符就绪或出错,0:仅仅检测文件描述符集的状态,然后立即返回,非0:在指定时间内,若没事发生,则超时返回。
在我们调用select时进程会一直阻塞有文件可以读有文件可以写超时所设置的时间到

文件描述符涉及到的宏void FD_SET(int fd, fd_set *fdset)//将FD加入到fdsetvoid FD_CLR(int fd, fd_set *fdset)//将fd从fdset里面清除void FD_ZERO(fd_set *fdset)//从fdset中清除所有的文件描述符void FD_ISSET(int fd, fd_set *fdset)//判断fd是否在fdset集合中
#include <sys/poll.h>int poll ( struct pollfd *fds,    //文件描述符                unsigned int nfds,   //关心的事件                int timeout )    //
UNIX环境高级编程——TCP/IP网络编程
底层:UNIX环境高级编程——TCP/IP网络编程

//select_server1.c
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>          /* See NOTES */#include <sys/time.h>#include <unistd.h>#include <sys/select.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <netinet/in.h>#include <arpa/inet.h>#define N 64 typedef struct sockaddr SA;int main(int argc, char *argv[]){    int listenfd, connfd, maxfd, i;    struct sockaddr_in servaddr, peeraddr;    socklen_t len;    char buf[N] = {0};    fd_set rdfs, bakrdfs;    ssize_t n;    if (argc < 3)    {        fprintf(stdout, "usage:%s <ip> <port>\n", argv[0]);        exit(0);    }    bzero(&servaddr, sizeof(servaddr));    if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)    {        perror("socket");        exit(-1);    }    servaddr.sin_family = PF_INET;    servaddr.sin_port = htons(atoi(argv[2]));    servaddr.sin_addr.s_addr = inet_addr(argv[1]);    if (bind(listenfd, (SA *)&servaddr, sizeof(servaddr)) == -1)      {               perror("bind");        exit(-1);    }    listen(listenfd, 5);    maxfd = listenfd;    FD_ZERO(&bakrdfs);    FD_SET(listenfd, &bakrdfs);    len = sizeof(peeraddr);    while (1)    {        rdfs = bakrdfs;        if (select(maxfd+1, &rdfs, NULL, NULL, NULL) == -1)        {            perror("select");            exit(-1);        }        for (i = 0; i <= maxfd; i++)        {            if (FD_ISSET(i, &rdfs))            {                if (i == listenfd)                {                    if ((connfd = accept(i, (SA *)&peeraddr, &len)) == -1)                    {                        perror("accept");                        exit(-1);                    }                    fprintf(stdout, "welcome %s %d\n",                             inet_ntoa(peeraddr.sin_addr),                             ntohs(peeraddr.sin_port));                    FD_SET(connfd, &bakrdfs);                    maxfd = (maxfd > connfd) ? maxfd : connfd;                }                else                {                    bzero(buf, sizeof(buf));                    if ((n = recv(i, buf, N, 0)) == 0)                    {                        close(i);                        FD_CLR(i, &bakrdfs);                    }                    else                    {                        printf("n=%d %s\n", n, buf);                        send(i, buf, N, 0);                    }                }            }        }    }    exit(0);}

//select_server2.c
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>          /* See NOTES */#include <sys/time.h>#include <unistd.h>#include <sys/select.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <netinet/in.h>#include <arpa/inet.h>#define N 64 typedef struct sockaddr SA;int main(int argc, char *argv[]){    int listenfd, connfd, maxfd, i;    struct sockaddr_in servaddr, peeraddr;    socklen_t len;    char buf[N] = {0};    fd_set rdfs;    if (argc < 3)    {        fprintf(stdout, "usage:%s <ip> <port>\n", argv[0]);        exit(0);    }    bzero(&servaddr, sizeof(servaddr));    if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)    {        perror("socket");        exit(-1);    }    servaddr.sin_family = PF_INET;    servaddr.sin_port = htons(atoi(argv[2]));    servaddr.sin_addr.s_addr = inet_addr(argv[1]);    if (bind(listenfd, (SA *)&servaddr, sizeof(servaddr)) == -1)      {               perror("bind");        exit(-1);    }    listen(listenfd, 5);    maxfd = listenfd;    FD_ZERO(&rdfs);    while (1)    {        FD_SET(0, &rdfs);        FD_SET(listenfd, &rdfs);        if (select(maxfd+1, &rdfs, NULL, NULL, NULL) == -1)        {            perror("select");            exit(-1);        }        for (i = 0; i <= maxfd; i++)        {            if (FD_ISSET(i, &rdfs))            {                if (i == 0)                {                    fgets(buf, N, stdin);                    printf("*************\n");                    printf("%s", buf);                }                else if (i == listenfd)                {                    len = sizeof(peeraddr);                    if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)                    {                        perror("accept");                        exit(-1);                    }                    fprintf(stdout, "welcome %s %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));                    close(connfd);                }            }        }    }    exit(0);}

//client.c
#include <stdio.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <netinet/in.h>#include <arpa/inet.h>typedef struct sockaddr SA;#define N 64int main(int argc, char *argv[]){    int sockfd;    ssize_t n;    struct sockaddr_in servaddr;    char buf[N] = {0};    if (argc < 3)    {        fprintf(stdout, "usage:%s ip port\n", argv[0]);        exit(0);    }    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)    {        perror("socket");        exit(-1);    }        bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = PF_INET;    servaddr.sin_port = htons(atoi(argv[2]));// "9000"---9000    servaddr.sin_addr.s_addr = inet_addr(argv[1]);    if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) == -1)    {        perror("connect");        exit(-1);    }    printf(">");    while (fgets(buf, N, stdin) != NULL)//abc\n     {        buf[strlen(buf)-1] = 0;//abc\0        send(sockfd, buf, N, 0);        bzero(buf, sizeof(buf));        n = recv(sockfd, buf, N, 0);        printf("n=%d buf=%s\n", n, buf);        printf(">");    }    close(sockfd);    exit(0);}


网络超时:

超时检测的必要性:
  • 避免无数据时无限制的阻塞
  • 设定的时间到时,进程从原操作返回继续运行

TCP套接字中的recv/accept/connect
UDP套接字中的recvfrom
都会造成阻塞
三种超时检测的方法:
1、设置socket的属性SO_RCVTIMEO
#include <stdio.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <netinet/in.h>#include <arpa/inet.h>typedef struct sockaddr SA;voidf(int sig) {printf("*\n");}int main(int argc, char *argv[]){    int listenfd, connfd;    struct sockaddr_in myaddr, peeraddr;    socklen_t len;    if (argc < 3)    {        fprintf(stdout, "usage:%s ip port\n", argv[0]);        exit(0);    }    if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)    {        perror("socket");        exit(-1);    }        bzero(&myaddr, sizeof(myaddr));    myaddr.sin_family = PF_INET;    myaddr.sin_port = htons(atoi(argv[2]));//htons(9000)    myaddr.sin_addr.s_addr = inet_addr(argv[1]);    int on = 1;    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)    {        perror("setsockopt");        exit(-1);    }    if (bind (listenfd, (SA *)&myaddr, sizeof(myaddr)) == -1)    {        perror("bind");        exit(-1);    }    if (listen(listenfd, 5) == -1)    {        perror("listen");        exit(-1);    }    bzero(&peeraddr, sizeof(peeraddr));    len = sizeof(peeraddr);    struct timeval t={5, 0};    if (setsockopt(listenfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t)) == -1)    {        perror("setsockopt");        exit(-1);    }    while (1)    {        if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)        {            printf("%d\n", errno);            exit(-1);        }        printf("welcome %s:%d\n", inet_ntoa(peeraddr.sin_addr),                ntohs(peeraddr.sin_port));        close(connfd);    }    exit(0);}

2、用select检测socket是否ready
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>          /* See NOTES */#include <sys/time.h>#include <unistd.h>#include <sys/select.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <netinet/in.h>#include <arpa/inet.h>#define N 64 typedef struct sockaddr SA;int main(int argc, char *argv[]){    int listenfd, connfd, maxfd, i;    struct sockaddr_in servaddr, peeraddr;    socklen_t len;    char buf[N] = {0};    fd_set rdfs;    if (argc < 3)    {        fprintf(stdout, "usage:%s <ip> <port>\n", argv[0]);        exit(0);    }    bzero(&servaddr, sizeof(servaddr));    if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)    {        perror("socket");        exit(-1);    }    servaddr.sin_family = PF_INET;    servaddr.sin_port = htons(atoi(argv[2]));    servaddr.sin_addr.s_addr = inet_addr(argv[1]);    if (bind(listenfd, (SA *)&servaddr, sizeof(servaddr)) == -1)      {               perror("bind");        exit(-1);    }    listen(listenfd, 5);    maxfd = listenfd;    int n;    FD_ZERO(&rdfs);    while (1)    {        struct timeval t = {5, 0};        FD_SET(0, &rdfs);        FD_SET(listenfd, &rdfs);        if ((n = select(maxfd+1, &rdfs, NULL, NULL, &t)) == -1)        {            perror("select");            exit(-1);        }        printf("n=%d\n", n);        for (i = 0; i <= maxfd; i++)        {            if (FD_ISSET(i, &rdfs))            {                if (i == 0)                {                    fgets(buf, N, stdin);                    printf("*************\n");                    printf("%s", buf);                }                else if (i == listenfd)                {                    len = sizeof(peeraddr);                    if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)                    {                        perror("accept");                        exit(-1);                    }                    fprintf(stdout, "welcome %s %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));                    close(connfd);                }            }        }    }    exit(0);}


3、设置定时器(timer),捕捉SIGALRMI信号
#include <stdio.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <netinet/in.h>#include <arpa/inet.h>typedef struct sockaddr SA;void f(int sig) {    printf("signo=%d\n", sig);    alarm(5);}int main(int argc, char *argv[]){    int listenfd, connfd;    struct sockaddr_in myaddr, peeraddr;    socklen_t len;    if (argc < 3)    {        fprintf(stdout, "usage:%s ip port\n", argv[0]);        exit(0);    }    if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)    {        perror("socket");        exit(-1);    }        bzero(&myaddr, sizeof(myaddr));    myaddr.sin_family = PF_INET;    myaddr.sin_port = htons(atoi(argv[2]));//htons(9000)    myaddr.sin_addr.s_addr = inet_addr(argv[1]);    if (bind (listenfd, (SA *)&myaddr, sizeof(myaddr)) == -1)    {        perror("bind");        exit(-1);    }    if (listen(listenfd, 5) == -1)    {        perror("listen");        exit(-1);    }    bzero(&peeraddr, sizeof(peeraddr));    len = sizeof(peeraddr);//    signal(SIGALRM, f);    struct sigaction act;    sigaction(SIGALRM, NULL, &act);    act.sa_handler = f;    sigaction(SIGALRM, &act, NULL);    printf("**\n");    while (1)    {        alarm(5);        if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)        {            printf("%d\n", errno);            exit(-1);        }        printf("welcome %s:%d\n", inet_ntoa(peeraddr.sin_addr),                ntohs(peeraddr.sin_port));        close(connfd);    }    exit(0);}


广播
只有数据报(UDP协议)才能够广播MAC:FF:FF:FF:FF:FF:FF
发送端
  • 创建用户数据报套接字
  • 缺省创建的套接字不允许广播数据包,需要设置属性
  • 接收方地址指定为广播地址
  • 指定端口信息
  • 发送数据包

流程
UNIX环境高级编程——TCP/IP网络编程

接收端
  • 创建用户数据报套接字
  • 绑定本机IP地址和端口(绑定的端口必须与发送方指定的端口相同)
  • 等待接收数据

流程UNIX环境高级编程——TCP/IP网络编程



//receiver.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>typedef struct sockaddr SA;#define N 64int main(int argc, char *argv[]){    int sockfd;    struct sockaddr_in myaddr, peeraddr;    socklen_t len;    char buf[N] = {0};    if (argc < 3)    {        fprintf(stdout, "usage:%s ip port\n", argv[0]);        exit(0);    }    if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)    {        perror("socket");        exit(-1);    }        bzero(&myaddr, sizeof(myaddr));    myaddr.sin_family = PF_INET;    myaddr.sin_port = htons(atoi(argv[2]));//6000    myaddr.sin_addr.s_addr = inet_addr(argv[1]);//0.0.0.0 192.168.1.255    if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)    {        perror("bind");        exit(-1);    }    len = sizeof(peeraddr);    bzero(&peeraddr, sizeof(peeraddr));    while (1)    {        bzero(buf, sizeof(buf));        if (-1 == recvfrom(sockfd, buf, N, 0, (SA *)&peeraddr, &len))        {            printf("errno=%d %s\n", errno, strerror(errno));            exit(-1);        }        printf("from %s:%d %s\n", inet_ntoa(peeraddr.sin_addr),                ntohs(peeraddr.sin_port), buf);    }    exit(0);}

//sender.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>typedef struct sockaddr SA;#define N 64int main(int argc, char *argv[]){    int sockfd;    struct sockaddr_in servaddr;    char buf[N] = {0};    if (argc < 3)    {        fprintf(stdout, "usage:%s ip port\n", argv[0]);        exit(0);    }    if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)    {        perror("socket");        exit(-1);    }    int on = 1;    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1)    {        perror("setsockopt");        exit(-1);    }        bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = PF_INET;    servaddr.sin_port = htons(atoi(argv[2]));// 6000    servaddr.sin_addr.s_addr = inet_addr(argv[1]);//192.168.1.255    strcpy(buf, "this is a broadcast package");    while (1)    {        sendto(sockfd, buf, N, 0, (SA *)&servaddr, sizeof(servaddr));        sleep(1);    }    close(sockfd);    exit(0);}

组播

组播地址:224.10.10.1MAC:01:00:5E:0A:0A:01

组播发送:
  • 创建用户数据报套接字
  • 接收方地址指定为组播地址
  • 指定端口信息
  • 发送数据包

组播接收
  • 创建用户数据报套接字
  • 加入多播组
  • 绑定本机IP地址和端口(绑定的端口必须和发送方指定的端口相同)
  • 等待接收数据

//sender.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>typedef struct sockaddr SA;#define N 64int main(int argc, char *argv[]){    int sockfd;    struct sockaddr_in servaddr;    char buf[N] = {0};    if (argc < 3)    {        fprintf(stdout, "usage:%s ip port\n", argv[0]);        exit(0);    }    if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)    {        perror("socket");        exit(-1);    }    bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = PF_INET;    servaddr.sin_port = htons(atoi(argv[2]));// 6000    servaddr.sin_addr.s_addr = inet_addr(argv[1]);//224.10.10.1    strcpy(buf, "this is a multicast package");    while (1)    {        sendto(sockfd, buf, N, 0, (SA *)&servaddr, sizeof(servaddr));        sleep(1);    }    close(sockfd);    exit(0);}

//receiver.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>typedef struct sockaddr SA;#define N 64int main(int argc, char *argv[]){    int sockfd;    struct sockaddr_in myaddr, peeraddr;    socklen_t len;    char buf[N] = {0};    struct ip_mreq mreq;    if (argc < 3)    {        fprintf(stdout, "usage:%s ip port\n", argv[0]);        exit(0);    }    if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)    {        perror("socket");        exit(-1);    }    bzero(&mreq, sizeof(mreq));    mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");    mreq.imr_interface.s_addr = htonl(INADDR_ANY);    if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)    {        perror("setsockopt");        exit(-1);    }        bzero(&myaddr, sizeof(myaddr));    myaddr.sin_family = PF_INET;    myaddr.sin_port = htons(atoi(argv[2]));//6000    myaddr.sin_addr.s_addr = inet_addr(argv[1]);//0.0.0.0 224.10.10.1    if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)    {        perror("bind");        exit(-1);    }    len = sizeof(peeraddr);    bzero(&peeraddr, sizeof(peeraddr));    while (1)    {        bzero(buf, sizeof(buf));        if (-1 == recvfrom(sockfd, buf, N, 0, (SA *)&peeraddr, &len))        {            printf("errno=%d %s\n", errno, strerror(errno));            exit(-1);        }        printf("from %s:%d %s\n", inet_ntoa(peeraddr.sin_addr),                ntohs(peeraddr.sin_port), buf);    }    exit(0);}


setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq);

UNIX环境高级编程——TCP/IP网络编程

                                     UNIX环境高级编程——TCP/IP网络编程

                                     UNIX环境高级编程——TCP/IP网络编程



UNIX域套接字

特点:
  • 常用于本地前后台进程通信
  • 创建套接字是使用本地协议PF_UNIX(或者PF_LOCAL)
  • 分为流式套接字和用户数据报套接字
  • 相对其他进程通信方式有使用方便,效率高的特点

本地地址结构体:

struct sockaddr_un    //<sys/un.h>{        sa_family_t sun_family;        char sun_path[108];    //套接字文件路径}使用:struct sockaddr_un myaddr;bzero(&myaddr,sizeof(myaddr));
myaddr.sun_family = PF_UNIX;strcpy(myaddr.sun_path,"mysocket");
UNIX域(流式)套接字

服务端
  • socker(PF_UNIX,SOCK_STREAM,0)
  • bind(,本地地址,)
  • listen(,)
  • accept(,,)
  • recv()/send()
  • ……

客户端
  • socker(PF_UNIX,SOCK_STREAM,0)
  • bind(,本地地址,)//可选
  • connect(, , )
  • recv()/send()
  • ……

//server.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <sys/un.h>typedef struct sockaddr SA;#define N 64int main(int argc, char *argv[]){    int listenfd, connfd;    struct sockaddr_un myaddr, peeraddr;    socklen_t len;    char buf[N] = {0};    ssize_t n;    if ((listenfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)    {        perror("socket");        exit(-1);    }        bzero(&myaddr, sizeof(myaddr));    myaddr.sun_family = PF_UNIX;    strcpy(myaddr.sun_path, "serversocket");    unlink("serversocket");    if (bind (listenfd, (SA *)&myaddr, sizeof(myaddr)) == -1)    {        perror("bind");        exit(-1);    }    if (listen(listenfd, 5) == -1)    {        perror("listen");        exit(-1);    }    bzero(&peeraddr, sizeof(peeraddr));    len = sizeof(peeraddr);    while (1)    {        if ((connfd = accept(listenfd, (SA *)&peeraddr, &len)) == -1)        {            perror("accept");            exit(-1);        }        printf("welcome %s\n", peeraddr.sun_path);        while (1)        {            bzero(buf, sizeof(buf));            if ((n = recv(connfd, buf, N, 0)) == 0)                break;            send(connfd, buf, N, 0);        }        close(connfd);    }    exit(0);}

//client.c
#include <stdio.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <sys/un.h>typedef struct sockaddr SA;#define N 64int main(int argc, char *argv[]){    int sockfd;    ssize_t n;    struct sockaddr_un servaddr,myaddr;    char buf[N] = {0};    if ((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)    {        perror("socket");        exit(-1);    }#if 1    bzero(&myaddr, sizeof(myaddr));    myaddr.sun_family = PF_UNIX;    strcpy(myaddr.sun_path, "clientsocket");    unlink("clientsocket");    if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)    {        perror("bind");        exit(-1);    }#endif        bzero(&servaddr, sizeof(servaddr));    servaddr.sun_family = PF_UNIX;    strcpy(servaddr.sun_path, "serversocket");    if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) == -1)    {        perror("connect");        exit(-1);    }    printf(">");    while (fgets(buf, N, stdin) != NULL)//abc\n     {        buf[strlen(buf)-1] = 0;//abc\0        send(sockfd, buf, N, 0);        bzero(buf, sizeof(buf));        n = recv(sockfd, buf, N, 0);        printf("n=%d buf=%s\n", n, buf);        printf(">");    }    close(sockfd);    exit(0);}


UNIX域(用户数据报)套接字

UNIX环境高级编程——TCP/IP网络编程
UNIX环境高级编程——TCP/IP网络编程

//client.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <string.h>#include <sys/un.h>typedef struct sockaddr SA;#define N 64int main(int argc, char *argv[]){    int sockfd;    struct sockaddr_un servaddr, myaddr;    socklen_t len;    char buf[N] = {0};    if ((sockfd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)    {        perror("socket");        exit(-1);    }        bzero(&myaddr, sizeof(myaddr));    myaddr.sun_family = PF_UNIX;    strcpy(myaddr.sun_path, "clientsocket");    unlink("clientsocket");    if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)    {        perror("bind");        exit(-1);    }    bzero(&servaddr, sizeof(servaddr));    servaddr.sun_family = PF_UNIX;    strcpy(servaddr.sun_path, "serversocket");    printf(">");    while (fgets(buf, N, stdin) != NULL)    {        buf[strlen(buf)-1] = 0;        sendto(sockfd, buf, N, 0, (SA *)&servaddr, sizeof(servaddr));        bzero(buf, sizeof(buf));        recvfrom(sockfd, buf, N, 0, NULL, NULL);        printf("%s\n", buf);        printf(">");    }    close(sockfd);    exit(0);}

//server.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>#include <strings.h>#include <string.h>#include <sys/un.h>typedef struct sockaddr SA;#define N 64int main(int argc, char *argv[]){    int sockfd;    struct sockaddr_un myaddr, peeraddr;    socklen_t len;    char buf[N] = {0};    if ((sockfd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1)    {        perror("socket");        exit(-1);    }        bzero(&myaddr, sizeof(myaddr));    myaddr.sun_family = PF_UNIX;    strcpy(myaddr.sun_path, "serversocket");    unlink("serversocket");    if (bind (sockfd, (SA *)&myaddr, sizeof(myaddr)) == -1)    {        perror("bind");        exit(-1);    }    len = sizeof(peeraddr);    bzero(&peeraddr, sizeof(peeraddr));    while (1)    {        bzero(buf, sizeof(buf));        if (-1 == recvfrom(sockfd, buf, N, 0, (SA *)&peeraddr, &len))        {            printf("errno=%d %s\n", errno, strerror(errno));            exit(-1);        }        printf("from %s: %s\n", peeraddr.sun_path, buf);         sendto(sockfd, buf, N, 0, (SA *)&peeraddr, sizeof(peeraddr));    }    exit(0);}