伪终端模型,主设备相当于键盘和显示器,而从设备相当于设备驱动。
打开主设备:
int open_ptym(char *slave_name, int buf_size){
char *ptr;
int fdm;
#if 0
if((fdm = open("/dev/ptmx",O_RDWR))<0){
perror("open ptmx\n");
return -1;
}
#endif
if((fdm = posix_openpt(O_RDWR)) < 0){
perror("open ptmx\n");
return -1;
}
/* 设置从设备的访问权限 */
if(grantpt(fdm) < 0){
perror("grantpt");
close(fdm);
return -2;
}
/* clear slave`s lock flag */
if(unlockpt(fdm) < 0){
perror("unlockpt");
close(fdm);
return -3;
}
if((ptr = (char *)ptsname(fdm)) == NULL){
perror("ptsname");
close(fdm);
return -4;
}
strncpy(slave_name,ptr,buf_size);
slave_name[buf_size - 1] = '\0';
printf("fdm:%d slave_name:%s\n",fdm,slave_name);
return fdm;
}
打开从设备:
int open_ptys(char *slave_name){
int fds;
if((fds = open(slave_name,O_RDWR)) < 0){
perror("open slave");
return -5;
}
printf("fds:%d\n",fds);
return fds; }
登录后fork子程序为网络端服务,使用fds接受fdm方向过来的数据,而fdm的数据来自网络,针对fdm的进出和socket-fd的进出一共四个方向的i/o使用select处理:
int fork_bash(int *fdm_ret){
int fds, fdm, ret;
char slave_name[15];
struct termios termios_my;
struct winsize win_size;
/* get termios/winsize */
tcgetattr(STDIN_FILENO,&termios_my);
ioctl(STDIN_FILENO,TIOCGWINSZ, (char *)&win_size);
/* open primary pty */
fdm = open_ptym(slave_name,15);
if(fdm < 0){
return -1;
}
int pid = fork();
if(pid>0){
*fdm_ret = fdm;
return pid;
}else if(pid < 0){
perror("fork fault!");
return -1;
}else if(pid == 0){
/* create new session 控制终端丢失 */
ret = setsid();
if(ret < 0){
return -1;
}
/* open slave pty 设置控制终端为此pty */
fds = open_ptys(slave_name);
if(fds < 0){
return -1;
}
//*fds_ret = fds;
/* set termios/winsize */
tcsetattr(fds, TCSANOW, &termios_my);
ioctl(fds, TIOCSWINSZ, (char *)&win_size);
//ioctl(fds, TIOCSCTTY, (char *)0);
/* stdin sdtout stderr bind pts*/
if((ret = dup2(fds,STDIN_FILENO)) != STDIN_FILENO){
return -1;
}
if((ret = dup2(fds,STDOUT_FILENO)) != STDOUT_FILENO){
return -1;
}
if((ret = dup2(fds,STDERR_FILENO)) != STDERR_FILENO){
return -1;
}
if(fds > 2){
close(fds);
}
ret = execl("/bin/bash","bash",NULL);
if(ret < 0){
perror("execl err!");
return -1;
}
}
}
select处理:
(这端代码未编译过,错了别找我,嘎嘎)
int loop_select(int fdm, int socket_fd){
/* init fd_set */
fd_set read_set,write_set, tmp_set;
FD_ZERO(&read_set);
FD_ZERO(&tmp_set);
FD_ZERO(&write_set);
FD_SET(fdm,&read_set);
FD_SET(socket_fd,&read_set);
tmp_set = read_set;
/* init buffer */
char buf_from_fdm[1024];
char buf_from_socket[1024];
memset(buf_from_socket, 0, 1024);
memset(buf_from_fdm, 0, 1024);
int buf_fdm_count= 0;
int buf_socket_count = 0;
/* select */
struct timeval t;
t.tv_sec = xx;
t.tv_usec = xxx;
int ret = 0;
while(1){
ret = select(Max(fdm,socket_fd)+1, &read_set, &write_set, NULL, &t);
if(ret < 0){
perror("select error:");
return -1;
}
/* read fdm */
if(FD_ISSET(fdm, &read_set)){
ret = read(fdm, &buf_from_fdm[buf_fdm_count], 1024 - buf_fdm_count);
if(ret < 0){
if(errno != EINTR){
perror("read fdm error:");
return -1;
}
}else{
buf_fdm_count += ret;
}
}
/* read socket */
if(FD_ISSET(socket, &read_set)){
ret = read(socket, &buf_from_socket[buf_socket_count], 1024 - buf_socket_count);
if(ret < 0){
if(errno != EINTR){
perror("read socket error:");
return -1;
}
}else{
buf_socket_count += ret;
}
}
/* write socket */
if(FD_ISSET(socket_fd, &write_set)){
char *p = buf_from_socket;
while(buf_socket_count != 0){
ret = write(socket_fd, p, buf_socket_count);
if(ret < 0){
if(errno != EINTR){
perror("write socket_fd error:");
return -1;
}else{
continue;
}
}
p += ret;
buf_socket_count -= ret;
}
}
/* write fdm */
if(FD_ISSET(fdm, &write_set)){
char *p = buf_from_socket;
while(buf_fdm_count != 0){
ret = write(fdm, p, buf_fdm_count);
if(ret < 0){
if(errno != EINTR){
perror("write fdm error:");
return -1;
}else{
continue;
}
}
p += ret;
buf_fdm_count -= ret;
}
}
/* reset fd_set */
read_set = tmpset;
FD_ZERO(&write_set);
if(buf_fdm_count > 0){
FD_SET(socket_fd, &write_set);
}
if(buf_socket_count > 0){
FD_SET(fdm, &write_set);
}
}
}