《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上跑的时候却是成功的。