#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define SA struct sockaddr
struct _SocketInfo
{
int pid;
int fd;
int status;
};
int write_fd(int fd, void *ptr, size_t nbytes, int sendfd);
int prefork_client(int fd);
int read_fd(int fd);
int main_server(int server_sockfd,
struct _SocketInfo *SInfo,
struct sockaddr_in clientaddr,
int preforknum);
int main(int argc, char **argv)
{
char buf_in[80];
int state;
int clilen;
int n,i,pid;
int preforknum;
int ppid;
int sv[2];
struct _SocketInfo *SocketArray;
int server_sockfd, client_sockfd;
struct sockaddr_in clientaddr, serveraddr;
if (argc != 2)
{
fprintf(stderr, "Usage: %s [prefork#]\n", argv[0]);
return 1;
}
preforknum = atoi(argv[1]);
if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Error");
return 1;
}
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(8083);
bind(server_sockfd, (SA *)&serveraddr, sizeof(serveraddr));
if ((state = listen(server_sockfd, 5))<0)
{
perror("listen error: ");
exit(0);
}
if(preforknum > 10)
{
fprintf(stderr,"Max preforknum is 10\n");
exit(0);
}
ppid = getpid();
// Socket Infomation Array
SocketArray = (void *)malloc(sizeof(struct _SocketInfo)*preforknum);
memset((void *)SocketArray, 0x00, sizeof(struct _SocketInfo)*preforknum);
for (i = 0; i < preforknum; i++)
{
socketpair(AF_LOCAL, SOCK_STREAM, AF_LOCAL, sv);
pid = fork();
if (pid < 0)
{
perror("fork error");
exit(0);
}
if (pid == 0)
{
dup2(sv[0], 0);
close(sv[1]);
close(sv[0]);
close(server_sockfd);
prefork_client(0);
}
else
{
close(sv[0]);
SocketArray[i].pid = pid;
SocketArray[i].fd = sv[1];
SocketArray[i].status = 1;
}
}
main_server(server_sockfd, SocketArray, clientaddr, preforknum);
}
int write_fd(int fd, void *ptr, size_t nbytes, int sendfd)
{
struct msghdr msg;
struct iovec iov[1];
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
*((int *) CMSG_DATA(cmptr)) = sendfd;
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
return(sendmsg(fd, &msg, 0));
}
int read_fd(int fd)
{
int n;
int recvfd;
char ptr;
struct iovec iov[1];
struct cmsghdr *cmptr;
struct msghdr msg;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = (void *)&ptr;
iov[0].iov_len = 1;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if ( (n = recvmsg(fd, &msg, 0)) <= 0)
{
perror("recvmsg Error");
return -1;
}
cmptr = CMSG_FIRSTHDR(&msg);
if ((cmptr == NULL))
{
perror("CMSG ERROR\n");
return -1;
}
recvfd = *((int *) CMSG_DATA(cmptr));
return recvfd;
}
int main_server(int server_sockfd,
struct _SocketInfo *SocketArray,
struct sockaddr_in clientaddr,
int preforknum)
{
int clilen;
int client_sockfd;
int i;
char ptr;
int n;
int maxfd;
fd_set readfds, allfds;
int data;
FD_ZERO(&readfds);
FD_SET(server_sockfd, &readfds);
for (i = 0; i < preforknum; i++)
{
FD_SET(SocketArray[i].fd, &readfds);
maxfd = SocketArray[i].fd;
printf("socketpair fd %d\n", maxfd);
}
printf("%d\n", maxfd+1);
allfds = readfds;
while(1)
{
readfds = allfds;
clilen = sizeof(clientaddr);
printf("select Wait\n");
n = select(maxfd + 1, &readfds, (fd_set *)0, (fd_set *)0, NULL);
printf("select Wait End %d\n", n);
if (n < 0) continue;
if (FD_ISSET(server_sockfd, &readfds))
{
printf("ACCEPT\n");
if ((client_sockfd = accept(server_sockfd, (SA *)&clientaddr, (size_t *)&clilen)) ==-1)
{
perror("accept error:");
close(client_sockfd);
}
else
{
for (i = 0; i < preforknum; i++)
{
if(SocketArray[i].status)
{
printf("SocketSend pid(%d) -> %d\n", SocketArray[i].pid, client_sockfd);
write_fd(SocketArray[i].fd, &ptr, 1, client_sockfd);
SocketArray[i].status = 0;
close(client_sockfd);
break;
}
}
if (i == preforknum)
{
fprintf(stderr, "max Client error\n");
close(client_sockfd);
}
}
}
for (i = 0; i < preforknum; i++)
{
if(FD_ISSET(SocketArray[i].fd, &readfds))
{
printf("OK Chield Data\n");
read(SocketArray[i].fd, (void *)&data, sizeof(data));
printf("(%d) : Read Data %d\n", SocketArray[i].fd, data);
if(data == 0)
{
SocketArray[i].status = 1;
}
}
}
}
}
int prefork_client(int fd)
{
int n;
char buf_in[80]={0x00,};
int sockfd;
int msg = 0;
printf("Child PID %d\n", getpid());
while(1)
{
sockfd = read_fd(fd);
for(;;)
{
if ((n = read(sockfd, buf_in, 79)) > 0)
{
write(sockfd, buf_in, strlen(buf_in));
}
else
{
printf("Client Socket Close\n");
write(fd, (void *)&msg, sizeof(msg));
close(sockfd);
break;
}
memset(buf_in, 0x00, sizeof(buf_in));
}
}
}