基于数据报的实现
//
//上一个版本是基于连接的实现,今天改了一个基于数据报的实现
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <strings.h>
#include<sys/wait.h>
#include <string.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#define FIFO_NAME "/home/907684/my_fifo_file"
//#define BUFFER_SIZE PIPE_BUF
#define BUFFER_SIZE 10
#define TEN_MEG (1024*10)
#define CONTROLLEN sizeof (struct cmsghdr) + sizeof (int)
#define false 0
#define true 1
#define LISTEN_QLEN 1024
int proccess_num=-1;
const char * share_path = "/home/907684/test/fd_send/share_fd";
const char * str_to_cli = "This is the second proccess speaking.\n";
//1,send socket fd
//2,recv socket fd
//3,client connect
//4,server listen -- accept
//5,get_share_fd() ?
//6,send msg to share_fd
void s_send_fd(int sockfd, int fd)
{
struct sockaddr_un addr = {0};
struct msghdr msg = {0};
char ccmsg[CMSG_SPACE(sizeof(fd))];
struct cmsghdr* cmsg; int rv;
msg.msg_name = (struct sockaddr*)&addr;
msg.msg_namelen = sizeof(addr);
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
*(int*)CMSG_DATA(cmsg) = fd;
msg.msg_control = ccmsg;
msg.msg_controllen = cmsg->cmsg_len;
msg.msg_flags = 0;
printf("sendmsg client fd[%d] to socket fd[%d]\n",fd, sockfd);
rv = sendmsg(sockfd, &msg, 0) ;
printf("sendmsg return %d \r\n",rv);
if(rv == -1)
{
if(errno == EAGAIN)
{
return;
}
else
{
//error
printf("sendmsg error, file fd is %d\n", fd);
//close fd_to_send out side
return;
}
}
else if( rv == 0 )
{
//close fd_to_send out side
return;
}
printf("send fd[%d] to shared file finish.\r\n", fd);
//close fd_to_send out side
}
//************************ recv socket fd
//client socket()--name socket--connect()
//server socket()--name socket--bind()--listen() ==> accept()
int cli_connect_usockfd(const char* path)
/* client creat unix domain socket. failed return -1. */
{
if( path == NULL )
{
printf("[%d]path error. \r\n",proccess_num);
return -1;
}
struct sockaddr_un addr = {0};
int fd;
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
printf("[%d]creat unix domain socket failed. \r\n",proccess_num);
return -1;
}
addr.sun_family = AF_UNIX; //mostly, PF_UNIX=AF_UNIX
strcpy(addr.sun_path, path);
if( connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1 ){
if(errno != EINPROGRESS) //for non-block
{
printf("[%d] connect unix domain socket failed, %d, %s\n",proccess_num, errno, strerror(errno));
return -1;
}
}
printf("[%d] connect unix domain socket ok.\n", proccess_num);
return fd;
}
//client socket()--name socket--connect()
//server socket()--name socket--bind()--listen() ==> accept()
int serv_listen_usockfd(const char* path)
/* server creat unix domain socket. failed return -1. */
{
struct sockaddr_un addr = {0};
int fd;
if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
printf("[%d]creat unix domain socket failed. \r\n",proccess_num);
return -1;
}
unlink(path); //in case it already exists.
addr.sun_family = AF_UNIX; //mostly, PF_UNIX=AF_UNIX
strcpy(addr.sun_path, path);
if( bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1 ){
printf("[%d] bind unix domain socket failed, %d, %s\n",proccess_num, errno, strerror(errno));
return -1;
}
printf("[%d] bind unix domain socket ok.\n", proccess_num);
if( listen(fd, LISTEN_QLEN) == -1 )
{
//close fd???????????????????????????????????????????????
printf("[%d] listen unix domain socket error.error:%d,msg:%s. \n", proccess_num, errno, strerror(errno));
return -1;
}
printf("[%d] listen unix domain socket ok.\n", proccess_num);
return fd;
}
static int serv_accept_usockfd(int listen_fd)
/* server accept unix domain socket. failed return -1. */
{
struct sockaddr_un addr = {0};
socklen_t len= sizeof(addr);
return accept(listen_fd,(struct sockaddr*)&addr,&len); //fd,Eagain,other --3 case ??????????????????????
/*
int report = CReportEngin::m_ReportListen.Accept();
if(report > 0)
{
if(false == m_ReportEngin->AddJob(report))
{
LOG_ERROR("[CACHESERVER] Failed to accept report.");
close(report);
}
}
else if(errno == EAGAIN)
return;
else
{
LOG_ERROR("[CACHESERVER] Failed to accept report." << strerror(errno));
return;
}
*/
}
int r_recv_fd(int fd)
/* recv internet socket fd. return value >0:succeed ,0:need retry, -1:failed. */
{
struct msghdr msg = {0};
int rv = 0;
int cfd = -1,client_fd=-1;
char ccmsg[CMSG_SPACE(sizeof(cfd))];
struct cmsghdr* cmptr;
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
rv = recvmsg(fd, &msg, 0);
if(rv == -1)
{
if(errno == EAGAIN)
{
return 0;
}
else
{
//error
printf("sendmsg error, file fd is %d\n", fd);
//close fd ????????????????????????????? sockfd do not close!!!
return -1;
}
}
else if( rv == 0 )
{
//error
//close fd ????????????????????????????? sockfd do not close!!!
return -1;
}
cmptr = CMSG_FIRSTHDR(&msg);
if((cmptr != NULL) && (cmptr->cmsg_len == CMSG_LEN(sizeof(int))))
{
if(cmptr->cmsg_level != SOL_SOCKET)
{
printf("control level != SOL_SOCKET/n");
return -1;
}
if(cmptr->cmsg_type != SCM_RIGHTS)
{
printf("control type != SCM_RIGHTS/n");
return -1;
}
client_fd = *((int*)CMSG_DATA(cmptr));
}
else
{
if(cmptr == NULL)
printf("null cmptr, fd not passed./n");
else
printf("message len[%d] if incorrect./n", cmptr->cmsg_len);
return -1;
}
printf("[%d]recieved client socket fd[%d].\n",proccess_num,client_fd);
return client_fd;
}
void send_msg_to_client(int cfd, const char* str)
{
printf("[%d]write string to recieved file fd[%d]. string[%s]\r\n",proccess_num, cfd,str);
int rv = write(cfd, str, strlen(str));
if(rv == -1)
{
if(errno == EAGAIN)
{
return;
}
else
{
//error
printf("[%d]sendmsg error, fd is %d\n",proccess_num, cfd);
//close fd ????????????????????????????? sockfd do not close!!!
return;
}
}
else if( rv == 0 )
{
//error
//close fd ?????????????????????
}
else
{
printf("[%d]finish send msg to client.",proccess_num);
//close fd ?????????????????????
}
}
//************************ recv socket fd
int main(int argc, char ** argv)
{
pid_t pid;
char *msg;
int n,i,j;
int exit_code;
int res=0,WR_fifo_fd,RD_fifo_fd;
int u_listen_fd, u_sock_fd2 ;
//***** socket *****
int s_listen_f,s_conn_fd;
socklen_t clilen;
struct sockaddr_in cliaddr,servaddr;
s_listen_f = socket(AF_INET,SOCK_STREAM,0);
//set non_block
int flags = fcntl(s_listen_f, F_GETFL, 0);
if( -1 == fcntl(s_listen_f, F_SETFL, flags|O_NONBLOCK) )
{
printf("Set NONBLOCK for socket fd %d failed", s_listen_f);
exit(1);
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(8060);
bind(s_listen_f, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));
listen(s_listen_f, 1024);
//***** socket *****
printf("start 2.\r\n");
for( i=0;i<3;i++)
{
pid=fork();
proccess_num=i;
if(pid == 0 || pid == -1)
{
printf(" not fork.\r\n");
break;
}
}
if (pid == -1)
{
printf("fork error.\r\n");
exit(1);
}
else if(pid == 0)
{
//child procces.
//********
printf("[%d] enter for...\r\n",proccess_num);
if (proccess_num == 1) // 1 write fifo
{
/*printf("[%d] init_fifo_write.\r\n",proccess_num);*/
u_sock_fd2 = cli_connect_usockfd(share_path); //inti unix domain socket client
if( u_sock_fd2 == -1 )
{
//error ???
return -1;
}
}
if (proccess_num == 2) // 2 read fifo
{
/*printf("[%d] init_fifo_read. \r\n",proccess_num);*/
//init listen unix domain socket.
u_listen_fd = serv_listen_usockfd(share_path);
if(u_listen_fd == -1)
{
printf("serv_listen_usockfd return %d ,errno:%d, msg:%s . \r\n", u_listen_fd, errno, strerror(errno) );
return -1;
}
}
printf("[%d] child loop call accept() .\r\n",proccess_num);
for(;;)
{
//printf("[%d] sleep 2 sec.\r\n",proccess_num);
sleep(1);
//read fifo .
if (proccess_num == 2) // 2 read Unix domain socket
{
int u_fd=-1;
//printf("[%d] fifo read.\r\n",proccess_num);
int shared_fd=-1;
// 1,put in unix domain socket listen main loop
u_fd = serv_accept_usockfd(u_listen_fd);
printf("accept return %d \r\n", u_fd);
if(u_fd == -1)
{
if(errno == EAGAIN)
{
continue;
}
else
{
printf("accept error %d \r\n",errno);
return -1;
}
}
// 2,add u_fd to epoll
// 3,when u_fd readable
shared_fd = r_recv_fd(u_fd); // return value ??????????????????????????????
if(shared_fd == 0)
{
printf("[%d] recv no fd, retry later. \r\n", proccess_num);
return;
}
else if( shared_fd == -1 )
{
printf("[%d] recv fd failed. \r\n", proccess_num);
//NOT close u_fd ??????
return;
}
// 4,add shared_fd to epoll
// 3,when shared_fd writeable
send_msg_to_client(shared_fd, str_to_cli);
close(shared_fd);
}
else if (proccess_num == 1) // 1 write Unix domain socket
{
clilen = sizeof(cliaddr);
//printf("[%d] child call accept() .\r\n",proccess_num);
// 1, put in internet socket listen main loop
if((s_conn_fd = accept(s_listen_f,(struct sockaddr*)&cliaddr, &clilen)) < 0)
{
//printf("[%d] accept failed. fd: %d.\r\n",proccess_num,s_conn_fd);
if(errno == EAGAIN)
{
//printf("[%d] accept EAGAIN.continue...\r\n",proccess_num);
continue;
}
else
{
printf("[%d] accept error.\r\n",proccess_num);
exit(1);
}
}
else
{
printf("[%d] accept succeed. fd:%d \r\n",proccess_num,s_conn_fd);
// 2,(when init unix domain socket)add u_sock_fd2 to epoll
// 3,when u_sock_fd2 is writeable
//send socket fd to other proccess!
s_send_fd(u_sock_fd2,s_conn_fd);
printf("[%d]send socket fd[%d] to other proccess finish. close socket fd. \r\n",proccess_num,s_conn_fd);
close(s_conn_fd);
}
}
}
}
else
{
//parent.
printf("parent wait...\r\n");
while(1);
printf("parent exit.\r\n");
exit(0);
}
}