《Unix/Linux编程实践教程》笔记(10)──连接到近端或远段的进程
内容
管道通过fork在进程中共享,socket则可以通过机器地址和端口识别连接。
客户服务系统包括通信系统和协议。客户和服务器通过管道或socket进行通信。协议是会话过程中一系列规则的集合。
利用fork,pipe,fdopen实现了一个简单的popen。
给文件描述符关联文件流 | fdopen(int fd, const char *mode) |
给程序关联一个指向程序标准输入或者输出的文件流 | popen(const char *command, const char *type) |
建立连接 | socket(int domain, int type, int protocol) |
绑定地址 | bind(int sockid, struct sockaddr addrp, socklen_t addrlen) |
监听 | listen(int sockid, int qsize) |
接收 | accept(int sockid, struct sockaddr * callerid, socklen_t * addrlenp) |
连接 | connect(int sockid, struct sockaddr * serv_addrp, socken_t addrlen |
获取ip地址 | gethostbyname() |
将点分十进制ip地址转成二进制 | inet_pton(AF_INET, SERVERADDR, &saddrcli.sin_addr); |
习题
11.6
重新写了一个函数,根据字符数组中的 \n 分割表达式,传给dc
be_tc_c(pipetodc, pipefromdc) int pipetodc[2], pipefromdc[2]; { int num1, num2; char operation[BUFSIZ], message[BUFSIZ], *fgets(), tmpmess[BUFSIZ]; FILE *fpout, *fpin, *fdopen(); close(pipetodc[0]); /* won't read from pipe to dc */ close(pipefromdc[1]); /* won't write to pipe from dc */ fpout = fdopen( pipetodc[1], "w" ); /* convert file desc- */ fpin = fdopen( pipefromdc[0], "r" ); /* riptors to streams */ if ( fpout == NULL || fpin == NULL ) fatal("Error convering pipes to streams"); /* * read from real stdin */ fflush(stdout); if ( fgets(message,BUFSIZ,stdin) == NULL ) /* get input */ exit(-1); /* parse it */ int size=strlen(message); for(int i = 0, j = 0; i < size; i++, j++) { tmpmess[j] = message[i]; if (message[i] == '\n') { tmpmess[j] = '\0'; j = 0; printf ("have newline %d\n", i); if ( sscanf(tmpmess, "%d%s%d", &num1,operation,&num2) != 3 ) { printf("syntax error\n"); continue; } if ( fprintf( fpout , "%d %d %c p\n", num1, num2, *operation ) == EOF ) fatal("Error writing"); fflush( fpout ); if ( fgets( tmpmess, BUFSIZ, fpin ) == NULL ) break; printf("%d %c %d = %s", num1, *operation , num2, tmpmess); } } fclose(fpout); /* close pipe */ fclose(fpin); /* dc will see EOF */ }
11.9
可以使用getpeername函数获得sock_fd中的客户端信息。
11.14
参考rlsd,把command改成finger。
11.15
在服务程序中再发起一个socket连接,从另一个程序中获取数据,返回给客户端。
服务程序 while(1) 中的部分
sock_fp = fdopen(sock_fd,"w"); /* we'll write to the */ if ( sock_fp == NULL ) /* socket as a stream */ oops( "fdopen" ); /* unless we can't */ if((sockcli_fd=socket(AF_INET, SOCK_STREAM, 0)) <0) oops("sockcli_fd"); bzero(&saddrcli, sizeof(saddrcli)); saddrcli.sin_family = AF_INET; saddrcli.sin_port = htons(SERVERPORT); inet_pton(AF_INET, SERVERADDR, &saddrcli.sin_addr); if (connect(sockcli_fd, (struct sockaddr *)&saddrcli, sizeof(struct sockaddr_in)) < 0) oops("connect sockclifd"); if ((n=read(sockcli_fd,buff, 512)) > 0) buff[n] = '\0'; fprintf(sock_fp, "%s", buff); fclose( sock_fp ); /* release connection */
结束
11.9 的程序有点奇怪,有时在本地跑的时候会报错 getpeername bad address ,但是放到vps上跑的时候却是成功的。