[内核版本]
linux-2.6.31
[尚存缺憾]
1、getsockopt和setsockopt的某些特定参数的调用(net/unix/af_unix.c中定义的*sockop函数均保留接口,返回EOPNOTSUPP错误);
2、ss命令查看到的本地socket状态需要进一步确认;
[注意事项]
1、使用本地socket进行通信时,其通信过程并不通过报文交互进行状态机切换:
a)server端在执行listen函数之后,该socket即处于监听状态;
b)client端在执行connect函数时,正常情况下,内核将sock状态设置为SS_CONNECTED,将sk状态设置为TCP_ESTABLISHED,然后通知server端有client请求(向server的socket发送SIGIO信号);
c)一旦出现某一情况导致server端的最大链接请求(应该是由sk_max_ack_backlog成员定义,在listen函数中指定)使用完毕,如果不设置连接超时时间,client端应该在2147483647秒的时间超时
// include/linux/kernel.h
#define LONG_MAX((long)(~0UL>>1))
// include/linux/sched.h
#defineMAX_SCHEDULE_TIMEOUTLONG_MAX
// net/core/sock.c
void sock_init_data(struct socket *sock, struct sock *sk)
{
...
sk->sk_sndtimeo=MAX_SCHEDULE_TIMEOUT;
...
}
2、本地socket和网络socket的通信机制有些不同(比如,tcp状态机不通过报文交互实现,getsockopt不能取到tcp的连接状态,内核在处理本地socket时,可能不会有一些协议栈的过程,即可能忽略了报文的完整性检查),很多网络socket上使用的函数在迁移至本地socket时需要酌情考虑。
[server端代码]
int ct_ipc_sock_create(struct ct_fd * sockfd, int server_flag)
{
log_debug("server_flag: %d", server_flag);
int ret = CT_RET_SUCCESS;
int result = 0;
struct sockaddr_un srv_addr;
memset(&srv_addr, 0, sizeof(struct sockaddr_un));
if (SERVER_SOCKET == server_flag)
{
sockfd->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
if (0 > sockfd->fd)
{
log_err("create Unix Socket error");
ret = CT_RET_SYS_SOCK_CREATE_ERR;
goto ct_ipc_sock_create_err;
}
srv_addr.sun_family=AF_UNIX;
strncpy(srv_addr.sun_path, UNIX_DOMAIN, sizeof(srv_addr.sun_path)-1);
unlink(UNIX_DOMAIN);
ret=bind(sockfd->fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
log_err("cannot bind server socket (%d)", sockfd->fd);
ret = CT_RET_SYS_SOCK_BIND_ERR;
goto ct_ipc_sock_bind_listen_err;
}
}
else if (CLIENT_SOCKET == server_flag)
{
sockfd->fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (0 > sockfd->fd)
{
log_err("create Unix Socket error");
ret = CT_RET_SYS_SOCK_CREATE_ERR;
goto ct_ipc_sock_create_err;
}
log_debug("sockfd: %d", sockfd->fd);
setsockopt(sockfd->fd, SOL_SOCKET, TCP_NODELAY, &result, sizeof(int));
srv_addr.sun_family=AF_UNIX;
strncpy(srv_addr.sun_path,
UNIX_DOMAIN_CLOUD,
sizeof(srv_addr.sun_path)-1);
unlink(UNIX_DOMAIN_CLOUD);
ret=bind(sockfd->fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
if(ret==-1)
{
log_err("cannot bind server socket (%d)", sockfd->fd);
ret = CT_RET_SYS_SOCK_BIND_ERR;
goto ct_ipc_sock_bind_listen_err;
}
log_debug("%s", strerror(errno));
ret=listen(sockfd->fd, MAX_LISTEN_BACKLOG);
if(ret==-1)
{
log_err("cannot listen the client connect request (%d)", sockfd);
ret = CT_RET_SYS_SOCK_LISTEN_ERR;
goto ct_ipc_sock_bind_listen_err;
}
}
else
{
}
log_debug("%s", strerror(errno));
return ret;
ct_ipc_sock_bind_listen_err:
close(sockfd->fd);
ct_ipc_sock_create_err:
sockfd->fd = -1;
return ret;
}
int ct_select_run()
{
int ret = CT_RET_SUCCESS;
fd_set rset, allset;
int nfds = 0;
int maxfd = 0;
int cloudfd = 0;
int read_num = 0;
int write_num = 0;
socklen_t addrLen;
struct sockaddr_in addr;
char rsp[] = "ACK";
char data_buf[MAX_BUF] = {0};
log_debug("sockfd: %d, nlfd.fd: %d, cloud_sockfd.fd: %d",
ipc_sockfd.fd, nlfd.fd, cloud_sockfd.fd);
group_filter_init();
maxfd = ipc_sockfd.fd ;
FD_ZERO(&allset);
FD_SET(cloud_sockfd.fd, &allset);
log_debug("sockfd: %d, maxfd: %d, cloud_sockfd.fd: %d",
ipc_sockfd.fd, maxfd, cloud_sockfd.fd);
while (1/*nfds == 0*/)
{
rset = allset;
log_debug("sockfd: %d", ipc_sockfd.fd);
nfds = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (0 > nfds)
{
log_err("select error: %s", strerror(errno));
ret = CT_RET_SYS_SOCK_SELECT_ERR;
return ret;
}
if (FD_ISSET(cloud_sockfd.fd, &rset)) {
log_debug("cloud_sockfd: %d", cloud_sockfd.fd);
cloudfd = accept(cloud_sockfd.fd,
(struct sockaddr *)&addr,
&addrLen);
if (cloudfd < 0) {
log_err("accept (%d) client error: %d", cloud_sockfd.fd, ret);
continue;
}
read_num = read(cloudfd, data_buf, MAX_BUF);
log_debug("client socket is: %d, read_num: %d",
cloudfd, read_num);
if (read_num > 0) {
write_num = write(cloudfd, sta_info,
(sizeof(sta_list_attr)*num +
sizeof(int)));
log_debug("client socket is: %d, write_num: %d",
cloudfd, write_num);;
}
}
close(cloudfd);
}
}
return ret;
}
[client端代码]
int do_filter_notify(cloud_cmd_attr * attr, char * buf, int buf_len)
{
int ret = 0;
int client_fd = -1;
char recv_buf[128] = {0};
struct sockaddr_un srv_addr;
int maxfd = 0;
int nfds = 0;
fd_set rset, allset;
struct timeval tv;
struct timeval t;
/* Wait up to five seconds. */
tv.tv_sec = CLI_TIME_OUT;
tv.tv_usec = 0;
memset(&srv_addr, 0, sizeof(struct sockaddr_un));
client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
log_debug("client_fd: %d\n", client_fd);
printf("client_fd: %d\n", client_fd);
if (-1 != client_fd)
{
t.tv_sec = UNIX_SOCK_CONNECT_TIMEO;
t.tv_usec = 0;
// 对于SOL_SOCKET的level,setsockopt将调用BSD socket提供的setsockopt,
// 否则将会调用sock本身绑定的setsockopt(AF_UNIX类型的setsockopt和
// getsockopt都返回EOPNOTSUPP错误)
ret = setsockopt(client_fd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
srv_addr.sun_family = AF_UNIX;
memcpy(srv_addr.sun_path, UNIX_DOMAIN_CLOUD, strlen(UNIX_DOMAIN_CLOUD));
log_debug("srv_addr.sun_path: %s\n", srv_addr.sun_path);
printf("srv_addr.sun_path: %s\n", srv_addr.sun_path);
ret = connect(client_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
if (-1 == ret)
{
log_err("error: %d, %s\n", errno, strerror(errno));
ret = CT_RET_SYS_SOCK_CONNECT_ERR;
goto close_fd;
}
else
{
int write_num = 0;
write_num = write(client_fd, attr, sizeof(cloud_cmd_attr));
if (sizeof(cloud_cmd_attr) == write_num)
{
FD_ZERO(&allset);
FD_SET(client_fd, &allset);
maxfd = client_fd;
rset = allset;
nfds = select(maxfd + 1, &rset, NULL, NULL, &tv);
log_debug("nfds: %d\n", nfds);
printf("nfds: %d\n", nfds);
if (FD_ISSET(client_fd, &rset))
{
int num = 0;
if (NULL == buf)
{
num = read(client_fd, recv_buf, sizeof(recv_buf));
}
else
{
num = read(client_fd, buf, buf_len);
}
if (num <= 0)
{
log_err("read %d error", client_fd);
ret = CT_RET_FD_READ_ERR;
}
else
{
log_debug("client_fd: %d, read length: %d", client_fd, num);
printf("client_fd: %d, read length: %d", client_fd, num);
if (NULL == buf)
{
log_debug("recv_buf: %s\n", recv_buf);
if (!strcasecmp(recv_buf, "ack"))
{
ret = CT_RET_SUCCESS;
}
}
else
{
// do nothing
}
}
goto close_fd;
}
else
{
log_err("no response from: %d", client_fd);
printf("no response from: %d", client_fd);
ret = CT_RET_SOCK_SELECT_TIMEOUT;
goto close_fd;
}
}
else
{
log_err("(%d) write to peer %s error (num: %d)", client_fd, UNIX_DOMAIN_CLOUD, ret);
printf("(%d) write to peer %s error (num: %d)", client_fd, UNIX_DOMAIN_CLOUD, ret);
ret = CT_RET_FD_WRITE_ERR;
goto close_fd;
}
}
}
else
{
log_err("create Unix socket error");
printf("create Unix socket error");
ret = CT_RET_SYS_SOCK_CREATE_ERR;
}
return ret;
close_fd:
close(client_fd);
client_fd = -1;
return ret;
}
转载于:https://blog.51cto.com/scottgh/1577623