zoukankan      html  css  js  c++  java
  • 基于TCP的C/S初级网络编程2

    导读

    本篇文章对http://www.daoluan.net/blog/?p=774中的“计算器”进行改进,与大家分享。

    上面那篇中的服务端属重复型,即一个时刻只处理一客户的请求,处理期间不搭理其他客户。此篇对上篇的“计算器”进行小小的改进——能够接受多个客户的请求。

    改进细则:

    1. 独立bind,listen,accept,serve(即calc过程)功能模块;
    2. 所有错误成功提示提取至各功能模块(函数)之外,错误/成功根据各函数的返回值判断(这更符合UNIX编程风范);
    3. 客户的服务过程由产生的子进程负责。

    缺陷:由子进程来负责serve的部分。服务器主进程(父进程)不负责等待子进程结束,资源由内核回收(这一要非必要)。

    上实验结果图片解解馋

    服务器启动

    客户端方面,将client1、client2和client3(编译链接自同一个代码)写进脚本。运行

    服务端服务多个客户请求

    client

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <string.h>
    
    #define MAXSLEEP 1024
    
    int connect_retry(int sockfd,const struct sockaddr * addr,socklen_t alen)
    {
        int nsec;
    
        printf("connecting\n");
        for(nsec = 1; nsec <= MAXSLEEP; nsec<<=1)
        {
            if(connect(sockfd,addr,alen) == 0)
            {
                printf("connected\n");
                return 0;
            }// if
            if(nsec <= MAXSLEEP/2)//    delay
                sleep(nsec);
        }// for:
        return 0;
    }
    
    int main(int argc,char * argv[])
    {
        if(argc != 4)
        {
            printf("you must input 4 arg\n");
            return 1;
        }// if
    
        int fd;    
        struct sockaddr_in si,server;
        char addr[20],buf[20],bufrecv[20];
    
        bzero(bufrecv,sizeof(bufrecv));
        sprintf(addr,"127.0.0.1");
    
        fd = socket(AF_INET,SOCK_STREAM,0);//   create socker fd;
        printf("socket ok\n");
    
    //prepare server addr
        bzero(&server,sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(6000);
        inet_pton(AF_INET,addr,(void *)&server.sin_addr);
        printf("server ok\n");
    
    //prepare request data
        bzero(buf,sizeof(buf));
        sprintf(buf,"%c%c%c",argv[1][0],argv[2][0],argv[3][0]);
    
    //connect
        if(connect_retry(fd,(struct sockaddr *)&server,sizeof(server)) < 0)
        {
            printf("connect error\n");
            return 1;
        }// if
    
    //send
        if(send(fd,buf,20,0) < 0) 
        {
            printf("client send error\n");
            return 1;
        }// if
    
    //select
        fd_set readfd;
        FD_ZERO(&readfd);
        FD_SET(fd,&readfd);
        int t;
    
        if((t = select(FD_SETSIZE,&readfd,NULL,NULL,NULL)) < 0)
        {
            printf("select error\n");
            return 1;
        }// if
    
    //recv
        bzero(bufrecv,sizeof(bufrecv));
        recv(fd,bufrecv,20,0);
        printf("%s\n",bufrecv);
    
        close(fd);
        return 0;
    }

    server

    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <errno.h>
    #include <ctype.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>
    
    char bufret[20];
    
    int initserver(int type,const struct sockaddr * addr,socklen_t alen,int qlen)
    {
        int fd;
        int err = 0;
    
        if((fd = socket(addr->sa_family,type,0)) < 0)
            return -1;
    
        printf("binding\n");
        if(bind(fd,addr,alen) < 0)
        {
            err = errno;
            goto errout;
        }// if
        printf("bind succeed \n");
    
        if(type == SOCK_STREAM || type == SOCK_SEQPACKET)
        {
            printf("listening\n");
            if(listen(fd,1) < 0)
            {
                err = errno;
                printf("listen error\n");
                goto errout;
            }// if
        }// if
        printf("listened \n");
        return (fd);
    
    errout:
        close(fd);
        errno = err;
        return -1;
    }
    
    int serve(int sockfd)
    {
        int a,b;
        char op,buf[25];
    
        int ret,addrlen = sizeof(struct sockaddr_in),clfd; 
        struct sockaddr_in client;
    
        bzero(&client,sizeof(client));
    
    //accept   
        printf("accepting\n");
        clfd = accept(sockfd,(struct sockaddr *)&client,&addrlen);
    
    //recv
        printf("accepted\n");
        bzero(buf,sizeof(buf));
        recv(clfd,buf,20,0);
        printf("recived\n");
    
    //calculate
        a = buf[0] - '0';
        b = buf[1] - '0';
        op = buf[2];
    
        switch(op)
        {
            case '+':ret = a + b;break;
            case '-':ret = a - b;break;
            case '*':ret = a * b;break;
            case '/':ret = a / b;break;
        }// switch
    
        sprintf(bufret,"the result:%d",ret);
    
    //send
        printf("sending\n");
        if(send(clfd,bufret,20,0) < 0)
        {
            printf("server send error\n");
            return -1;
        }// if
        printf("sended,server end\n");
        return 0;
    }
    
    int main(int argc,char * argv[])
    {
        int sockfd;
        char addr[20];
    
        bzero(addr,sizeof(addr));
        sprintf(addr,"127.0.0.1");
    
        struct sockaddr_in server;
        bzero(&server,sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(6000);
        //server.sin_addr.s_addr = htonl(INADDR_ANY);
        inet_pton(AF_INET,addr,(void *)&server.sin_addr);
    
    //prepare server
    	while(1)
    	{
    	    if((sockfd = initserver(SOCK_STREAM,(struct sockaddr *)&server,sizeof(server),1)) < 0)
    	    {
    	        printf("initserver error\n");
    	        return 0;
    	   	}// if
    
    	   	pid_t pid;
    	   	if(pid = fork() < 0)	//	fork error
    	   	{
    	   		close(sockfd);
    	   		return -1;
    	   	}
    	   	else if(pid == 0)
       		{
       			printf("serving\n");
       			serve(sockfd);
       			break;
       		}//	if
    	}//	while
    
    //serve
        close(sockfd);
        return 0;
    }

    test.sh

    #!/bin/bash
    
    ./client1 1 2 +
    ./client2 2 3 +
    ./client3 3 4 +

    本文完 2012-08-06

    捣乱小子 http://www.daoluan.net/blog/

  • 相关阅读:
    创建你自己的依赖注入容器Ioc Container(转) dodo
    LINQ to XML 介绍(转) dodo
    使用jquery修复ie6/7不支持focus的bug dodo
    ASP.NET MVC 2强类型HTML辅助方法 dodo
    Ioc容器Autofac介绍 dodo
    serverU上传中文文件乱码 dodo
    LINQ语法二 dodo
    DIV+CSS解决IE6,IE7,IE8,FF兼容问题 dodo
    依赖注入容器Autofac与MVC集成 dodo
    mvc VIEW部分介绍 dodo
  • 原文地址:https://www.cnblogs.com/daoluanxiaozi/p/2625701.html
Copyright © 2011-2022 走看看