网络IPC

本文来自个人博客:https://dunkwan.cn

字节序

​ 同一台主机上进程间通信是不需要考虑字节序问题的,但是在网络上的不同主机上进程进行通信时,则要考虑字节序问题。

​ 字节序是一个处理器架构特性,用于指示像整数这样的大数据类型内部的字节如何排序。当处理器架构支持大端字节序,那么最大字节地址出现在最低有效字节上(Least Significant Byte, LSB)。不管字节如何排序,最高有效字节(Most Significant Byte, MSB)总是在左边,最低有效字节总是在右边。当处理器架构支持小端字节序时,则最低有效字节包含最小字节地址。如下面例子所示,可以对处理器的大小端进行判断。

#include <func.h>

void bigEndianOrLittleEndian()
{
    int n = 0x04030201;
    char *cp =(char *)&n;
    if(cp[0] == 1 && cp[3] == 4)
        printf("This platform is little endian.\n");
    else if(cp[0] == 4 && cp[3] == 1)
        printf("This platform is big endian.\n");
}

int main(void)
{
    bigEndianOrLittleEndian();
    return 0;
}

​ 如上面所示,当一个整型数被强制转换成字符指针时,在小端处理器上,cp[0]指向最低有效字节因而包含1,cp[3] 指向最高有效字节因而包含4。相比较而言,在大端处理器上,cp[0]指向最高有效字节因而包含4,cp[3]指向最低有效字节因而包含1。下图展示了32位整数中的字节序。

socket函数

socket函数用于创建套接字

#include <sys/socket.h>
int socket(int domain, int type, int protocol);
返回值:若成功,返回文件(套接字)描述符;若出错,返回-1

domain取值情形如下:


type取值情形如下:

protocol取值情形如下:通常为0,表示为给定的域和套接字类型选择默认协议。

connect函数

connect函数用于建立连接。

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
返回值:若成功,返回0;若出错,返回-1

bind函数

bind函数用于关联地址和套接字。

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
返回值:若成功,返回0;若出错,返回-1

listen函数

listen函数用于宣告服务器愿意接受连接请求。

#include <sys/socket.h>
int listen(int sockfd, int backlog);
返回值:若成功,返回0;若出错,返回-1

发送数据函数

#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
返回值:若成功,返回发送的字节数;若出错,返回-1。
ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flags, const struct sockaddr *destaddr, socklen_t destlen);
返回值:若成功,返回发送的字节数;若出错,返回-1。
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
返回值:若成功,返回发送的字节数;若出错,返回-1

接收数据函数

#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
返回值:返回数据的字节长度;若无可用数据或对等方已经按序结束,返回0;若出错,返回-1。
ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags, struct sockaddr *restrict addr, socklen_t *restrict addrlen);
返回值:返回数据字节长度;若无可用数据或对等方已经按序结束,返回0;若出错,返回-1。
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
返回值:返回数据的字节长度;若无可用数据或对等方已经按序结束,返回0;若出错,返回-1

测试示例1:

面向连接的客户服务器模型。

/*  client  module */
#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h>

#define BUFLEN 128

extern int connect_retry(int ,int, int, const struct sockaddr *, socklen_t);

void print_uptime(int sockfd)
{
    int n;
    char buf[BUFLEN];

    while((n = recv(sockfd, buf, BUFLEN, 0)) > 0)
        write(STDOUT_FILENO, buf, n);
    if(n < 0)
        err_sys("recv error");
}

int main(int argc, char *argv[])
{
    struct addrinfo *ailist , *aip;
    struct addrinfo hint;
    int sockfd, err;

    if(argc != 2)
        err_quit("usage: ruptime hostname");

    memset(&hint, 0, sizeof(hint));
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;

    if((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)
        err_quit("getaddrinfo error: %s", gai_strerror(err));
    for(aip = ailist; aip != NULL; aip = aip->ai_next){
        if((sockfd = connect_retry(aip->ai_family, SOCK_STREAM, 0, aip->ai_addr, 
                                    aip->ai_addrlen)) < 0){
            err = errno;
        }else{
            print_uptime(sockfd);
            exit(0);
        }
    }
    err_exit(err, "can't connect to %s", argv[1]);
}

/* server module*/
#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <syslog.h>
#include <sys/socket.h>

#define BUFLEN 128
#define QLEN 10

#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 256
#endif

extern int initserver(int, const struct sockaddr *, socklen_t, int);

void serve(int sockfd)
{
    int clfd;
    FILE *fp;
    char buf[BUFLEN];

    set_cloexec(sockfd);
    for(;;){
        if((clfd = accept(sockfd, NULL, NULL)) < 0){
            syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno));
            exit(1);
        }
        set_cloexec(clfd);
        if((fp = popen("/usr/bin/uptime", "r")) == NULL){
            sprintf(buf, "error: %s\n", strerror(errno));
            send(clfd, buf, strlen(buf), 0);
        }else{
            while(fgets(buf, BUFLEN, fp) != NULL)
                send(clfd, buf, strlen(buf), 0);
            pclose(fp);
        }
        close(clfd);
    }
}

int main(int argc, char *argv[])
{
    struct addrinfo *ailist, *aip;
    struct addrinfo hint;
    int sockfd, err, n;
    char *host;

    if(argc != 1)
        err_quit("usage: ruptimed");
    if((n = sysconf(_SC_HOST_NAME_MAX)) < 0)
        n = HOST_NAME_MAX;
    if((host = (char *)malloc(n)) == NULL)
        err_sys("malloc error");
    if(gethostname(host, n) < 0)
        err_sys("gethostname error");
    daemonize("ruptimed");
    memset(&hint, 0, sizeof(hint));
    hint.ai_flags = AI_CANONNAME;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;

    if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0){
        syslog(LOG_ERR, "ruptimed: getaddrinfo error: %s", gai_strerror(err));
        exit(1);
    }
    for(aip = ailist; aip != NULL; aip = aip->ai_next){
        if((sockfd = initserver(SOCK_STREAM , aip->ai_addr, aip->ai_addrlen,
                                QLEN)) >= 0){
                serve(sockfd);
                exit(0);
        }
    }

    exit(1);
}

测试示例2:
面向无连接客户服务器模型。

/* client module */
#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h>

#define BUFLEN 128
#define TIMEOUT 20

void sigalrm(int signo)
{

}

void print_uptime(int sockfd, struct addrinfo *aip)
{
    int n;
    char buf[BUFLEN];

    buf[0] = 0;
    if(sendto(sockfd, buf, 1, 0, aip->ai_addr, aip->ai_addrlen) < 0)
        err_sys("sendto error");

    alarm(TIMEOUT);

    if((n = recvfrom(sockfd, buf, BUFLEN, 0, NULL, NULL)) < 0){
        if(errno != EINTR)
            alarm(0);
        err_sys("recv error");
    }
    alarm(0);
    write(STDOUT_FILENO, buf, n);

}

int main(int argc, char *argv[])
{
    struct addrinfo *ailist, *aip;
    struct addrinfo hint;
    int sockfd, err;
    struct sigaction sa;
    
    if(argc != 2)
        err_quit("usage: ruptime hostname");
    sa.sa_handler = sigalrm;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    if(sigaction(SIGALRM, &sa, NULL) < 0)
        err_sys("sigaction error");
    memset(&hint, 0, sizeof(hint));
    hint.ai_socktype = SOCK_DGRAM;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;

    if((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)
        err_quit("getaddrinfo error: %s", gai_strerror(err));

    for(aip = ailist; aip != NULL; aip = aip->ai_next){
        if((sockfd = socket(aip->ai_family, SOCK_DGRAM, 0)) < 0){
            err = errno;
        }else{
            print_uptime(sockfd, aip);
            exit(0);
        }
    }

    fprintf(stderr, "can't contact %s: %s\n", argv[1], strerror(err));
    exit(1);
}

/* server module */
#include "apue.h"
#include <netdb.h>
#include <errno.h>
#include <syslog.h>
#include <sys/socket.h>

#define BUFLEN 128
#define MAXADDRLEN 256

#ifdef HOST_NAME_MAX
#define HOST_NAME_MAX 256
#endif

extern int initserver(int, const struct sockaddr *, socklen_t, int);

void serve(int sockfd)
{
    int n;
    socklen_t alen;
    FILE *fp;
    char buf[BUFLEN];
    char abuf[MAXADDRLEN];
    struct sockaddr *addr = (struct sockaddr *)abuf;

    set_cloexec(sockfd);

    for(;;){
        alen = MAXADDRLEN;
        if((n = recvfrom(sockfd, buf, BUFLEN, 0, addr, &alen)) < 0){
            syslog(LOG_ERR, "ruptimed: recvfrom error: %s", strerror(errno));
            exit(1);
        }
        if((fp = popen("/usr/bin/uptime", "r")) == NULL){
            sprintf(buf, "error: %s\n", strerror(errno));
            sendto(sockfd, buf, strlen(buf), 0, addr, alen);
        }else{
            if(fgets(buf, BUFLEN, fp) != NULL)
                sendto(sockfd, buf, strlen(buf), 0, addr, alen);
            pclose(fp);
        }
    }
}

int main(int argc, char *argv[])
{
    struct addrinfo *ailist, *aip;
    struct addrinfo hint;
    int sockfd, err, n;
    char *host;

    if(argc != 1)
        err_quit("usage: ruptimed");
    if((n = sysconf(_SC_HOST_NAME_MAX)) < 0)
        n = _SC_HOST_NAME_MAX;

    if((host = (char *)malloc(n)) == NULL)
        err_sys("malloc error");
    if(gethostname(host, n) < 0)
        err_sys("gethostname error");

    daemonize("ruptimed");

    memset(&hint, 0, sizeof(hint));
    hint.ai_flags = AI_CANONNAME;
    hint.ai_socktype = SOCK_DGRAM;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;

    if((err = getaddrinfo(host, "ruptime", &hint, &ailist)) != 0){
        syslog(LOG_ERR,"ruptimed: getaddrinfo error: %s", gai_strerror(err));
        exit(1);
    }

    for(aip = ailist; aip != NULL; aip = aip->ai_next){
        if((sockfd = initserver(SOCK_DGRAM, aip->ai_addr, 
                                aip->ai_addrlen, 0)) >= 0){
            serve(sockfd);
            exit(0);
        }
    }
    exit(1);
}

源代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值