基於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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM