Linux下的tty和pts:PTS之间标准输入输出的交互

目录

目录结构

ptsTalk.h

ptsTalk.c

示例程序

master.c

slave.c

makefile

效果:


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 *~

效果:

发布了554 篇原创文章 · 获赞 269 · 访问量 48万+

猜你喜欢

转载自blog.csdn.net/Rong_Toa/article/details/103781124
今日推荐