目录
pts为伪终端,他们之间的标准输出输入该如何进行交换呢?
目录结构
# tree
.
├── Makefile
├── master
├── master.c
├── ptsTalk
│?? ├── ptsTalk.c
│?? └── ptsTalk.h
├── slave
└── slave.c
1 directory, 7 files
ptsTalk.h
#ifndef _TALK_PTS_H
#define _TALK_PTS_H 1
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
struct pts_id {
#define PTS_MAGIC 0xaab12cdd
int pts_magic;
int pts_dev_name;
int pts_pid;
};
typedef enum {
PTS_ON,
PTS_OFF,
}pts_stat;
typedef int (*pts_connect_fn)(struct pts_id*, pts_stat stat);
int pts_master(pts_connect_fn fn);
int pts_slave(struct pts_id*);
int pts_print(struct pts_id *pts, char *fmt, ...);
#endif//_TALK_PTS_H
ptsTalk.c
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <sys/select.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include "ptsTalk.h"
#define __PTS_UNSOCKET_PATH "/tmp/__pts_tell"
#define PTS_MAX_SLAVE 10
#define STR_LEN 256
#define PTS_PREFIX "/dev/pts"
pthread_t __pts_tell_tid;
static int __pts_master_listenfd;
static int __pts_tell_unsocket_server(const char *unix_path);
static int __pts_tell_unsocket_client(const char *unix_path);
static void* __pts_tell_master_task(void*arg);
static int pts_get_id(struct pts_id *tellpts);
void __pts_tell_unsocket_server_handle_sigint(int signum)
{
printf("Catch the SIGINT signal.\n");
close(__pts_master_listenfd);
unlink(__PTS_UNSOCKET_PATH);
exit(1);
}
void __pts_tell_unsocket_client_handle_sigint(int signum)
{
printf("Catch the SIGINT signal.\n");
exit(1);
}
int pts_master(pts_connect_fn fn)
{
return pthread_create(&__pts_tell_tid, NULL, &__pts_tell_master_task, fn);
}
int pts_slave(struct pts_id *tpts)
{
int connect_fd;
int ret = 0;
struct sockaddr_un srv_addr;
int i;
signal(SIGINT, __pts_tell_unsocket_client_handle_sigint);
connect_fd = __pts_tell_unsocket_client(__PTS_UNSOCKET_PATH);
struct pts_id tellpts;
pts_get_id(&tellpts);
write(connect_fd, &tellpts, sizeof(tellpts));
read(connect_fd, tpts, sizeof(struct pts_id));
close(connect_fd);
}
static int pts_get_id(struct pts_id *tellpts)
{
tellpts->pts_magic = PTS_MAGIC;
tellpts->pts_pid = getpid();
tellpts->pts_dev_name = 9999;
char cmd[256] = {0};
char str[256] = {0};
sprintf(cmd, "ps -ef | grep %d | awk '{print $6}'", tellpts->pts_pid);
FILE *fp = popen(cmd, "r");
fgets(str, sizeof(str), fp);
sscanf(str, "pts/%d", &tellpts->pts_dev_name);
pclose(fp);
return 0;
}
static void* __pts_tell_master_task(void*arg)
{
pts_connect_fn slave_connect_callback = (pts_connect_fn)arg;
struct {
int fd;
struct pts_id ptsid;
}slaves[PTS_MAX_SLAVE];
int connfd;
int ret = 0;
int i;
int len, msglen;
struct sockaddr_un clt_addr, srv_addr;
struct pts_id pts_tell;
char msg[STR_LEN];
int maxfd, maxi, nready;
fd_set readset, allset, exceptset;
int sockfd;
signal(SIGINT, __pts_tell_unsocket_server_handle_sigint);
__pts_master_listenfd = __pts_tell_unsocket_server(__PTS_UNSOCKET_PATH);
setsockopt(__pts_master_listenfd,SOL_SOCKET,SO_REUSEADDR,NULL,0);
setsockopt(__pts_master_listenfd,SOL_SOCKET,SO_REUSEPORT,NULL,0);
for(i=0; i<PTS_MAX_SLAVE; ++i)
{
slaves[i].fd = -1;
}
maxfd = __pts_master_listenfd;
maxi = -1;
FD_ZERO(&allset);
FD_SET(__pts_master_listenfd, &allset);
chmod(__PTS_UNSOCKET_PATH, 0777);
while(1)
{
readset = allset;
nready = select(maxfd+1, &readset, NULL, &exceptset, NULL);
if(nready <= 0)
{
perror("select error");
close(__pts_master_listenfd);
unlink(__PTS_UNSOCKET_PATH);
break;
}
if(FD_ISSET(__pts_master_listenfd, &readset))
{
len = sizeof(clt_addr);
connfd = accept(__pts_master_listenfd, (struct sockaddr*)&clt_addr, &len);
if(connfd < 0)
{
perror("cannot accept client connect request.");
close(__pts_master_listenfd);
unlink(__PTS_UNSOCKET_PATH);
break;
}
for(i=0; i<PTS_MAX_SLAVE; ++i)
{
if(slaves[i].fd < 0)
{
slaves[i].fd = connfd;
break;
}
if(PTS_MAX_SLAVE == i)
{
perror("too many connection.\n");
exit(1);
}
}
FD_SET(connfd, &allset);
if(connfd > maxfd)
{
maxfd = connfd;
}
if(i > maxi)
{
maxi = i;
}
}
for(i=0; i<=maxi; ++i)
{
if((sockfd = slaves[i].fd ) < 0)
{
continue;
}
if(FD_ISSET(sockfd, &readset))
{
memset(msg, 0, STR_LEN);
msglen = read(sockfd, msg, sizeof(msg));
if(msglen < 0)
{
close(sockfd);
FD_CLR(sockfd, &allset);
slaves[i].fd = -1;
}
int *magic = (int *)msg;
if(*magic == PTS_MAGIC)
{
memcpy(&slaves[i].ptsid, msg, sizeof(pts_tell));
memcpy(&pts_tell, msg, sizeof(pts_tell));
slave_connect_callback((struct pts_id*)&pts_tell, PTS_ON);
struct pts_id tellpts;
pts_get_id(&tellpts);
write(sockfd, &tellpts, sizeof(tellpts));
}
}
//Exception fd peer
if(FD_ISSET(sockfd, &exceptset))
{
if((sockfd = slaves[i].fd ) < 0)
{
continue;
}
close(sockfd);
FD_CLR(sockfd, &allset);
memcpy(&pts_tell, &slaves[i].ptsid, sizeof(pts_tell));
slave_connect_callback((struct pts_id*)&pts_tell, PTS_OFF);
slaves[i].fd = -1;
}
}
}
close(__pts_master_listenfd);
}
static int __pts_tell_unsocket_server(const char *unix_path)
{
int __pts_master_listenfd, ret = -1;
struct sockaddr_un srv_addr;
__pts_master_listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(__pts_master_listenfd < 0)
{
perror("sreate listening socket error.");
return -1;
}
srv_addr.sun_family = AF_UNIX;
strncpy(srv_addr.sun_path, unix_path, sizeof(srv_addr.sun_path)-1);
ret = bind(__pts_master_listenfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
if(ret == -1)
{
perror("cannot bind server socket.");
close(__pts_master_listenfd);
unlink(unix_path);
return -1;
}
ret = listen(__pts_master_listenfd, 1);
if(ret == -1)
{
perror("cannot listen the client connect request.");
close(__pts_master_listenfd);
unlink(unix_path);
return -1;
}
return __pts_master_listenfd;
}
static int __pts_tell_unsocket_client(const char *unix_path)
{
int connect_fd, ret = -1;
struct sockaddr_un srv_addr;
connect_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if(connect_fd < 0)
{
perror("create socket error.");
return -1;
}
srv_addr.sun_family = AF_UNIX;
strcpy(srv_addr.sun_path, unix_path);
ret = connect(connect_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
if(ret == -1)
{
perror("connect error");
close(connect_fd);
return -1;
}
return connect_fd;
}
static int ttysend(int fd, char *buf, size_t size)
{
size_t i;
for (i = 0; i < size; ++i)
if (ioctl(fd, TIOCSTI, buf + i) == -1)
return -1;
return 0;
}
int pts_print(struct pts_id *pts, char *fmt, ...)
{
char pts_name[256] = {0};
char line[1024] = {0};
char echo[1100] = {0};
int i;
sprintf(pts_name, "%s/%d", PTS_PREFIX, pts->pts_dev_name);
va_list va;
va_start(va, fmt);
int n = vsprintf(line, fmt, va);
va_end(va);
#if 0
/**
* 作为terminal的输入
*/
int fd = open(pts_name, O_RDWR);
ttysend(fd, line, strlen(line));
close(fd);
#elif 1
/**
* 作为terminal的输出
*/
int fd = open(pts_name, O_RDWR);
write(fd, line, strlen(line));
close(fd);
#else
/**
* 直接印屏echo
*/
sprintf(echo, "echo \"%s\" > %s", line, pts_name);
system(echo);
#endif
return n;
}
示例程序
master.c
#include <stdio.h>
#include "ptsTalk.h"
int slaves_connect_callback(struct pts_id* slave_info, pts_stat stat)
{
printf("Get a slave.\n");
int i;
for(i=0;i<3;i++)
{
pts_print(slave_info, "Get a slave. %d\n", i);
sleep(1);
}
return 0;
}
int main()
{
pts_master(&slaves_connect_callback);
while(1)
{
sleep(2);
}
return 0;
}
slave.c
#include <stdio.h>
#include "ptsTalk.h"
int main()
{
struct pts_id master;
pts_slave(&master);
pts_print(&master, ">>>>>>>>>>>>>>>>>>>>>>>>>I got it.\n");
while(1)
{
sleep(2);
}
return 0;
}
makefile
LIBS+= ptsTalk/ptsTalk.c
INCLUDE+=-I ptsTalk
LIB+=-lm -pthread -lrt
ALL:
gcc master.c -o master ${LIBS} ${LIB} ${INCLUDE}
gcc slave.c -o slave ${LIBS} ${LIB} ${INCLUDE}
clean:
rm *~