UNIX環境高級編程——TCP/IP網絡編程 經常使用網絡信息檢索函數

經常使用網絡信息檢索函數

gethostname()
 
getppername()
 
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()調用已執行。




系統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.
例:
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多路複用併發服務器流程 


#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加入到fdset
void 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 )    //

底層:
 

//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 64

int 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
都會形成阻塞

三種超時檢測的方法:

一、設置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);
}

二、用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);
}


三、設置定時器(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

發送端
  • 建立用戶數據報套接字
  • 缺省建立的套接字不容許廣播數據包,須要設置屬性
  • 接收方地址指定爲廣播地址
  • 指定端口信息
  • 發送數據包

流程


 
接收端
  • 建立用戶數據報套接字
  • 綁定本機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 64

int 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 64

int 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.1
MAC: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 64

int 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 64

int 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域套接字

特色: 
  • 經常使用於本地先後臺進程通訊
  • 建立套接字是使用本地協議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 64


int 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 64

int 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域(用戶數據報)套接字

 


//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 64

int 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 64

int 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);
}
相關文章
相關標籤/搜索