linux - socket

socket

      • 不得不提的是select
      • AF_INET域与AF_UNIX域socket通信原理对比
        • demo1
      • 在unix域中unlink的功能
        • demo2 --- (使用epoll解决多客户端连接)

不得不提的是select

#include    
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    108struct sockaddr_un { sa_family_t sun_family;               // AF_UNIX char        sun_path[UNIX_PATH_MAX];  // pathname 
};

demo1

server端

#include
#include
#include
#include
#include
#include
#include
//#include #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_UNIXservaddr.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
#include
#include
#include
#include
#include
#include
#include
//#include #define MAXLINE 4096 int main(int argc, char** argv)
{int sockfd, n;char recvline[4096], sendline[4096];struct sockaddr_in servaddr;  // sockaddr_unif( argc != 3){printf("usage: ./client \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_UNIXservaddr.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
#include
#include
#include
#include
#include
#include
#include 
#include 
#include #define MAXLINE 4096 
#define EPOLL_MAX_EVENTS 16int 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
#include
#include
#include
#include
#include
#include
#include
#include #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 \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);
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部