linux - socket

不得不提的是select

#include <sys/select.h>   
int select(int maxfdp1, fd_set *readset, fd_set *writeset, 
		fd_set *exceptset,struct timeval *timeout);

有三种情况:

  • timeout == NULL 等待无限长的时间。等待可以被一个信号中断。当有一个描述符做好准备或者是捕获到一个信号时函数会返回。如果捕获到一个信号, select函数将返回 -1,并将变量 erro设为 EINTR。
    • timeout == NULL在什么情况的时候会被打断()
  • timeout->tv_sec == 0 &&timeout->tv_usec == 0不等待,直接返回。加入描述符集的描述符都会被测试,并且返回满足要求的描述符的个数。这种方法通过轮询,无阻塞地获得了多个文件描述符状态。
  • timeout->tv_sec !=0 || timeout->tv_usec!= 0 等待指定的时间。当有描述符符合条件或者超过超时时间的话,函数返回。在超时时间即将用完但又没有描述符合条件的话,返回 0。对于第一种情况,等待也会被信号所中断。
    • 返回 0,表示超时
    • 返回-1,所有描述集清0
    • 当返回为正数时,表示已经准备好的描述符数。

AF_INET域与AF_UNIX域socket通信原理对比

1 建立socket传递的地址域,及bind()的地址结构稍有区别:

socket() 分别传递不同的域AF_INET和AF_UNIX

bind()的地址结构分别为sockaddr_in(制定IP端口)和sockaddr_un(指定路径名)

2 AF_INET需经过多个协议层的编解码,消耗系统cpu,并且数据传输需要经过网卡,受到网卡带宽的限制。AF_UNIX数据到达内核缓冲区后,由内核根据指定路径名找到接收方socket对应的内核缓冲区,直接将数据拷贝过去,不经过协议层编解码,节省系统cpu,并且不经过网卡,因此不受网卡带宽的限制。

3 AF_UNIX的传输速率远远大于AF_INET

3 AF_INET不仅可以用作本机的跨进程通信,同样的可以用于不同机器之间的通信,其就是为了在不同机器之间进行网络互联传递数据而生。而AF_UNIX则只能用于本机内进程之间的通信。

// *IPV6
struct sockaddr_in6 { 
    sa_family_t     sin6_family;   // AF_INET6 
    in_port_t       sin6_port;     // port number  
    uint32_t        sin6_flowinfo; // IPv6 flow information 
    struct in6_addr sin6_addr;     // IPv6 address 
    uint32_t        sin6_scope_id; // Scope ID (new in 2.4) 
};

struct in6_addr { 
    unsigned char   s6_addr[16];   // IPv6 address 
};

Unix域对应的是: 

#define UNIX_PATH_MAX    108

struct sockaddr_un { 
    sa_family_t sun_family;               // AF_UNIX 
    char        sun_path[UNIX_PATH_MAX];  // pathname 
};

demo1

server端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
//#include <sys/un.h>

#define MAXLINE 4096 
int main(int argc, char** argv)
{
        int listenfd, connfd;
        struct sockaddr_in servaddr; // struct sockaddr_un servaddr;
        char buff[4096];
        int n;
        if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) // AF_UNIX
        {
                printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
                exit(0);
        }
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;	//AF_UNIX
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //
        servaddr.sin_port = htons(6066); // strcpy(servaddr.sun_path, "server_socket");
        //unlink("server_socket"); //在unix域会创建一个server_socket文件来操作,unlink是删除server_socket的意思
        if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
        {
                printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
                exit(0);
        }
        if( listen(listenfd, 100) == -1)
        {
                printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
                exit(0);
        }
        printf("======waiting for client's request======\n");
        while(1)
        {
                if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1)
                {
                        printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
                        continue;
                }
                printf("begin recv  ");
                n = recv(connfd, buff, MAXLINE, 0);
                buff[n] = '\0';
                printf("server recv msg from ..%d..%d.. client: %s...\n", listenfd, connfd, buff);
                if( send(connfd,"11", 2, 0) < 0)
                {
                        printf("send failed\n");
                }
                close(connfd);
        }
        close(listenfd);
}

client端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
//#include <sys/un.h>

#define MAXLINE 4096 

int main(int argc, char** argv)
{
        int sockfd, n;
        char recvline[4096], sendline[4096];

        struct sockaddr_in servaddr;  // sockaddr_un
        if( argc != 3)
        {
                printf("usage: ./client <ipaddress>\n");
                exit(0);
        }
        while(1)
        {
                if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) // AF_UNIX
                {
                        printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
                        close(sockfd);
                        exit(0);
                }
                printf("sockfd = %d\n",sockfd);
                memset(&servaddr, 0, sizeof(servaddr));
                servaddr.sin_family = AF_INET; // AF_UNIX
                servaddr.sin_port = htons(6066); //
                /* AF_UNIX 下面要屏蔽*/
                if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
                {
                        printf("inet_pton error for %s\n",argv[1]); exit(0);
                }
                /* AF_UNIX 上面要屏蔽*/
                if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
                {
                        printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
                        close(sockfd);
                }
                strcpy(sendline,argv[2]);
                printf("send %s\n",argv[2]);
                if( send(sockfd, sendline, strlen(sendline), 0) < 0)
                {
                        printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
                        exit(0);
                }
                int n = recv(sockfd, recvline, MAXLINE, 0);
                if(n > 0){
                        printf("recv %s \n",recvline);
                }
                sleep(1);
                close(sockfd);
        }
        exit(0);
}

在unix域中unlink的功能

如果未加unlink("");可能会报如下错误

bind socket error: Address already in use(errno: 98)

demo2 — (使用epoll解决多客户端连接)

server 端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <sys/epoll.h>

#define MAXLINE 4096 
#define EPOLL_MAX_EVENTS 16

int mEpollFd = -1;
static const int EPOLL_SIZE_HINT = 8;

int epoll_init()
{
        mEpollFd = epoll_create(EPOLL_SIZE_HINT);
        if(mEpollFd < 0)
                return -1;
        return 0;
}

int epoll_addevent(int event_fd, int itemvalue)
{
        int result;
        struct epoll_event eventItem;
        eventItem.events = EPOLLIN;
        eventItem.data.u32 = itemvalue;//mINotifyFd;
        result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, event_fd, &eventItem);
        printf("epoll_ctl..EPOLL_CTL_ADD.. result = %d\n",result);
        return 0;
}
int epoll_rmevent(int event_fd)
{
        int result;
        result = epoll_ctl(mEpollFd, EPOLL_CTL_DEL,  event_fd , NULL);
        return result;
}

int main(int argc, char** argv)
{
        int listenfd, connfd, readfd;
        struct sockaddr_un servaddr; //struct sockaddr_in servaddr;
        char buff[4096];
        int n ,i;
        int timeoutMillis = -1;
        int ipollResult;
        struct epoll_event mPendingEventItems[16];

        if(epoll_init() >= 0){
                printf("epill init success !\n");
        }else{
                exit(0);
        }
        if( (listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ) //if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
        {
                printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
                exit(0);
        }
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sun_family = AF_UNIX; //servaddr.sin_family = AF_INET;
        strcpy(servaddr.sun_path, "serversocket_unix"); //servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        unlink("serversocket_unix");
        //servaddr.sin_port = htons(6066);
        if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
        {
                printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
                exit(0);
        }
        if( listen(listenfd, 100) == -1)
        {
                printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
                exit(0);
        }
        printf("======waiting for client's request======\n");
        epoll_addevent(listenfd, 0x1234);
        while(1)
        {
                printf("epoll wait\n");
                ipollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS
                                , timeoutMillis);
                printf("ipollResult = %d\n", ipollResult);
                for(i = 0; i < ipollResult; i++){
                        printf("mPendingEventItems->fd=%d\n",mPendingEventItems[i].data.u32);
                        printf("reason : 0x%x\n",mPendingEventItems[i].events);
                        if(mPendingEventItems[i].data.u32 == 0x1234){
                                printf("...hava new connect...\n");
                                if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1)
                                {
                                        printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
                                        continue;
                                }
                                else{
                                        epoll_addevent(connfd, connfd);
                                        printf("add connfd = %d\n",connfd);
                                }
                        }else{
                        //注意如果reason为0x11代表此连接被关闭
                                readfd = mPendingEventItems[i].data.u32;
                                if(mPendingEventItems[i].events == 0x11){
                                        epoll_rmevent(readfd);
                                        close(readfd); // 关闭已经断开的客户端
                                }else{
                                        printf("begin recv  connfd=%d, listenfd=%d\n", connfd, listenfd);
                                        n = recv(readfd, buff, MAXLINE, 0);
                                        buff[n] = '\0';
                                        printf("server recv msg from ..%d..%d.. client: %s...\n", listenfd, readfd, buff);
                                        if( send(readfd,"11", 2, 0) < 0)
                                        {
                                                printf("send failed\n");
                                        }
                                }
                        }
                }
        }
        close(connfd);
        close(listenfd);
}

client 端

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include <sys/un.h>

#define MAXLINE 4096 

int main(int argc, char** argv)
{
        int sockfd, n;
        int ret, i;
        char recvline[4096], sendline[4096];

        struct sockaddr_un serv_addr; //struct sockaddr_in servaddr;
        if( argc != 2)
        {
                printf("usage: ./client <message>\n");
                exit(0);
        }
        {
                if( (sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) //if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
                {
                        printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
                        close(sockfd);
                        exit(0);
                }
                printf("sockfd = %d\n",sockfd);
                memset(&serv_addr, 0, sizeof(serv_addr));
                serv_addr.sun_family = AF_UNIX; //servaddr.sin_family = AF_INET;
                strcpy(serv_addr.sun_path, "serversocket_unix"); //servaddr.sin_port = htons(6066);
              
                if( connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
                {
                        printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
                        close(sockfd);
                }
                strcpy(sendline,argv[1]);
                for(i = 0; i < 3; i++)
                {
                        printf("send %s, sockfd=%d\n",argv[1], sockfd);
                        //下面如果是服务端未继续进行监听此连接(也就是每次重新accept),会直接退出程序
                        if( (ret = send(sockfd, sendline, strlen(sendline), 0)) < 0 )
                        {
                                printf("send failed\n");
                                printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
                                //exit(0);
                        }
                        printf("send return = %d\n", ret);
                        int n = recv(sockfd, recvline, MAXLINE, 0);
                        if(n > 0){
                                printf("recv %s \n",recvline);
                        }
                        sleep(1);
                }
                close(sockfd);
        }
        exit(0);
}

猜你喜欢

转载自blog.csdn.net/LHshooter/article/details/86691712