问题描述
主进程中创建一个子进程和两个线程,每个线程负责accept连接,用socketpair创建了通信管道,在主进程中把服务端socket及管道的其中一个套接字传递给了线程,本来想在线程中把客户端socket文件描述符通过sendmsg函数传递给子进程,但是提示无效的文件描述符。
相关代码
struct mypara
{
int tcp_sock;//参数1
int pip_sock;//参数2
};
int main(int argc, char const *argv[])
{
int serv_sock;
struct sockaddr_in serv_adr;
pthread_t t_id[NUM_THREAD];
int j,k,state,str_len,fd,rv;
pid_t pid;
int fds[2];
struct sigaction act;
struct mypara pstru;
char buf[BUF_SIZE];
if(argc!=2)
{
printf("Usage: %s \n", argv[0]);
exit(1);
}
//注册信号处理函数
act.sa_handler=read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
state=sigaction(SIGCHLD,&act,0);
serv_sock=socket(PF_INET,SOCK_STREAM,0);
memset(&serv_adr,0,sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_adr.sin_port=htons(atoi(argv[1]));
if(bind(serv_sock,(struct sockaddr *)&serv_adr,sizeof(serv_adr))==-1)
error_handling("bind()...error");
if(listen(serv_sock,5)==-1)
error_handling("listen()...error");
//pipe(fds); //创建管道
socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
if (rv < 0)
{
printf("Call socketpair error, errno is %d\n", errno);
return errno;
}
pid=fork();
pstru.tcp_sock = serv_sock;
pstru.pip_sock = fds[1];
if(pid==0) /*子进程处理逻辑*/
{
close(serv_sock);//子进程销毁服务端套接字,因为不需要使用
puts("work start...");
while(1)
{
fd = recv_fd(fds[0]);
str_len = read(fds[0],buf,BUF_SIZE);//读
if (str_len > 0)
puts(buf);
if (fd > 0){
write(fd,buf,str_len);
}
}
return 0;
}
for (j = 0; j < NUM_THREAD; j++)
{
pthread_create(&t_id[j],NULL,handle_clnt,(void*)&pstru);
}
for(k=0;k
pthread_join(t_id[k],NULL);
return 0;
}
//每个线程执行的main入口函数
void * handle_clnt(void * arg)
{
struct mypara *pstru;
pstru = (struct mypara *) arg;
int serv_sock = pstru->tcp_sock; //tcp服务端描述符
int pip_sock = pstru->pip_sock; //管道描述符
int clnt_sock;
struct sockaddr_in clnt_adr;
socklen_t adr_sz;
int str_len,i;
char buf[BUF_SIZE];//接收数据
struct epoll_event *ep_events;
struct epoll_event event;
int epfd,event_cnt;
epfd=epoll_create(EPOLL_SIZE);
ep_events=malloc(sizeof(struct epoll_event)*EPOLL_SIZE);
event.events=EPOLLIN;
event.data.fd=serv_sock;
epoll_ctl(epfd,EPOLL_CTL_ADD,serv_sock,&event);
while(1)
{
event_cnt=epoll_wait(epfd,ep_events,EPOLL_SIZE,-1);
if(event_cnt==-1)
{
puts("epoll_wait() error");
break;
}
puts("return epoll_wait");
for(i=0;i
{
if(ep_events[i].data.fd==serv_sock)
{
adr_sz=sizeof(clnt_adr);
clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
event.events=EPOLLIN;
event.data.fd=clnt_sock;
epoll_ctl(epfd,EPOLL_CTL_ADD,clnt_sock,&event);
printf("connected client: %d \n", clnt_sock);
}
else
{
str_len=read(ep_events[i].data.fd,buf,BUF_SIZE);
if(str_len==0)
{
epoll_ctl(epfd,EPOLL_CTL_DEL,ep_events[i].data.fd,NULL);
close(ep_events[i].data.fd);
printf("closed client: %d \n", ep_events[i].data.fd);
}
else
{
write(pip_sock,buf,str_len);//写
send_fd(pip_sock, ep_events[i].data.fd);
//write(ep_events[i].data.fd,buf,str_len);
}
}
}
}
close(serv_sock);
close(epfd);
return NULL;
}
void read_childproc(int sig)
{
pid_t pid;
int status;
pid=waitpid(-1,&status,WNOHANG);
printf("removed proc id: %d \n", pid);
}
void error_handling(char *msg)
{
fputs(msg,stderr);
fputc('\n',stderr);
exit(1);
}
int send_fd(int fd, int fd_to_send)
{
struct msghdr msg;
struct iovec iov[1];
char buf[100];
union { //保证cmsghdr和msg_control对齐
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *pcmsg;
int ret;
//udp需要,tcp无视
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = buf;
iov[0].iov_len = 100;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
//设置缓冲区和长度
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
//直接通过CMSG_FIRSTHDR取得附属数据
pcmsg = CMSG_FIRSTHDR(&msg);
pcmsg->cmsg_len = CMSG_LEN(sizeof(int));
pcmsg->cmsg_level = SOL_SOCKET;
pcmsg->cmsg_type = SCM_RIGHTS; //指明发送的是描述符
*((int*)CMSG_DATA(pcmsg)) == fd_to_send; //把描述符写入辅助数据
ret = sendmsg(fd, &msg, 0);
if(ret < 0) {
printf("sendmsg error, errno is %d\n", errno);
printf("%s\n",strerror(errno));
printf ("ret = %d, filedescriptor = %d\n", ret, fd_to_send);
return errno;
}
return 0;
}
int recv_fd(int fd)
{
struct msghdr msg;
struct iovec iov[1];
char buf[100];
int ret,recvfd;
union { //对齐
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr * pcmsg;
msg.msg_name = NULL;
msg.msg_namelen = 0;
//设置数据缓冲区
iov[0].iov_base = buf;
iov[0].iov_len = 100;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
//设置辅助数据缓冲区和长度
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
//接收
ret = recvmsg(fd , &msg, 0);
if( ret <= 0 ) {
return ret;
}
//检查是否收到了辅助数据,以及长度
if((pcmsg = CMSG_FIRSTHDR(&msg) ) != NULL && ( pcmsg->cmsg_len == CMSG_LEN(sizeof(int)))) {
if ( pcmsg->cmsg_level != SOL_SOCKET ) {
printf("cmsg_leval is not SOL_SOCKET\n");
return -1;
}
if ( pcmsg->cmsg_type != SCM_RIGHTS ) {
printf ( "cmsg_type is not SCM_RIGHTS" );
return -1;
}
//这就是我们接收的描述符
recvfd = *((int*)CMSG_DATA(pcmsg));
return recvfd;
}
return -1;
}
错误信息:
sendmsg error, errno is 9
Bad file descriptor
ret = -1, filedescriptor = 8