针对 sylixos 应用手册中 15.5 AF_UNIX 域协议
UNIX 域套接字是一种高级的IPC 机制,这种形式的IPC 可以在同一计算机系统上运行的两个进程之间进行通信。虽然因特网域套接字可用于同一目的,但UNIX 域套接字的效率更高。UNIX 域套接字仅仅复制数据,并不执行协议处理,因此,无需添加或者删除网络报头,无需计算校验和,无需产生序列号,无需发送确认报文等。
本次针对非阻塞方式
服务端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <string.h>
#define AF_UNIX_FILE "afunix.tmp"
int main (int argc, char **argv)
{
printf("Hello SylixOS!\n");
int ssockfd, csockfd;
socklen_t slen, clen;
struct sockaddr_un saddr;
int i, bytes;
char str[16];
unlink(AF_UNIX_FILE);
ssockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (ssockfd < 0) {
fprintf(stderr, "[server]socket error.\n");
return (-1);
}
slen = sizeof(saddr);
strcpy(saddr.sun_path, AF_UNIX_FILE);
saddr.sun_family = AF_UNIX;
#if 1
int opt = fcntl(ssockfd, F_GETFL, 0);
printf("F_GETFL:0x%x\n",opt);
if (opt == -1) {
printf("fcntl getfl fail. errno=%d\n", errno);
// return false;
}
int ret;
if (0)
ret = fcntl(ssockfd, F_SETFL, opt & ~O_NONBLOCK);
else
ret = fcntl(ssockfd, F_SETFL, opt | O_NONBLOCK);
if (ret == -1) {
printf("fcntl setfl fail. errno=%d\n", errno);
// return false;
}
// return true;
#endif
bind(ssockfd, (struct sockaddr *) &saddr, slen);
listen(ssockfd, 5);
fprintf(stdout, "[server]waiting for client connect...\n");
ACCEPT:
csockfd = accept(ssockfd, (struct sockaddr *) &saddr, &clen);
if (csockfd < 0) {
if(errno == EAGAIN)
goto ACCEPT;
fprintf(stderr, "[server]%d: %s.\n",errno,strerror(errno));
perror("server:");
fprintf(stderr, "[server]accept error.\n");
close(ssockfd);
return (-1);
}
fprintf(stdout, "[server]connect success.\n");
for (i = 0; i < 500; i++) {
bytes = read(csockfd, str, 16);
if (bytes < 0) {
if(ECONNRESET == errno)
goto ACCEPT;
fprintf(stderr, "[server]%d: %s.\n",errno,strerror(errno));
perror("Error:");
fprintf(stderr, "[server]read error.\n");
// break;
}
if (strncmp("client", str, 6) == 0) {
fprintf(stdout, "[server]receiver from client is: %s\n", str);
} else {
fprintf(stderr, "[server]client send failed.\n");
break;
}
sleep(1);
fprintf(stdout, "[server]server reply ACK.\n");
bytes = write(csockfd, "ACK", 4);
if (bytes < 0) {
if(ECONNRESET == errno)
goto ACCEPT;
fprintf(stderr, "[server]%d: %s.\n",errno,strerror(errno));
perror("Error:");
fprintf(stderr, "[server]write error.\n");
// break;
}
fprintf(stderr, "[server]%d\n", i);
}
unlink(AF_UNIX_FILE);
close(csockfd);
close(ssockfd);
return (0);
}
客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#define AF_UNIX_FILE "afunix.tmp"
int main (int argc, char **argv)
{
printf("Hello SylixOS!\n");
fd_set fdr, fdw;
struct timeval timeout;
int err = 0;
int errlen = sizeof(err);
int sockfd;
struct sockaddr_un addr;
socklen_t len;
int i, bytes, result;
char str[16];
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
fprintf(stderr, "[client]socket error.\n");
return (-1);
}
#if 1
int opt = fcntl(sockfd, F_GETFL, 0);
printf("F_GETFL:0x%x\n",opt);
if (opt == -1) {
printf("fcntl getfl fail. errno=%d\n", errno);
// return false;
}
int ret;
if (0)
ret = fcntl(sockfd, F_SETFL, opt & ~O_NONBLOCK);
else
ret = fcntl(sockfd, F_SETFL, opt | O_NONBLOCK);
if (ret == -1) {
printf("fcntl setfl fail. errno=%d\n", errno);
// return false;
}
// return true;
#endif
bzero(&addr, sizeof(addr));
len = sizeof(addr);
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, AF_UNIX_FILE);
result = connect(sockfd, (struct sockaddr *) &addr, len);
if (result < 0) {
fprintf(stderr, "[client]connect error.\n");
fprintf(stderr, "[client]%d: %s.\n",errno,strerror(errno));
if (errno == EINPROGRESS) {
printf("Doing connection.\n");
/*正在处理连接*/
FD_ZERO(&fdr);
FD_ZERO(&fdw);
FD_SET(sockfd, &fdr);
FD_SET(sockfd, &fdw);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
ret = select(sockfd + 1, &fdr, &fdw, NULL, &timeout);
printf("ret is: %d\n", ret);
/*select调用失败*/
if (ret < 0) {
fprintf(stderr, "connect error:%s\n", strerror(errno));
close(sockfd);
return -1;
}
/*连接超时*/
if (ret == 0) {
fprintf(stderr, "Connect timeout.\n");
close(sockfd);
return -1;
}
/*[1] 当连接成功建立时,描述符变成可写,rc=1*/
if (ret == 1 && FD_ISSET(sockfd, &fdw)) {
printf("Connect success\n");
for (i = 0; i < 10; i++) {
bytes = write(sockfd, "client", 7);
if (bytes < 0) {
fprintf(stderr, "[client]write error.\n");
break;
}
sleep(2);
bytes = read(sockfd, str, 16);
if (bytes < 0) {
fprintf(stderr, "[client]read error.\n");
// break;
}
fprintf(stdout, "[client]receive ACK from server.\n");
}
close(sockfd);
return 0;
}
/*[2] 当连接建立遇到错误时,描述符变为即可读,也可写,rc=2 遇到这种情况,可调用getsockopt函数*/
if (ret == 2) {
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
fprintf(stderr, "getsockopt(SO_ERROR): %s", strerror(errno));
close(sockfd);
return -1;
}
if (err) {
errno = err;
fprintf(stderr, "connect error:%s\n", strerror(errno));
close(sockfd);
return -1;
}
}
}
fprintf(stderr, "[client]connect error.\n");
close(sockfd);
// return (-1);
}
fprintf(stdout, "[client]connect server success.\n");
close(sockfd);
return (0);
}