HOME | Links | About | Read

《Unix/Linux编程实践教程》笔记(10)──连接到近端或远段的进程

Table of Contents

内容

管道通过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上跑的时候却是成功的。