基於TCP的C/S初級網路編程1

來源:互聯網
上載者:User
 導讀

本篇實現C/S架構的“計算機”,與大家分享。

看了會網路編程,便不自覺YY了下:實現一個簡單的計算機,用戶端給出簡單的運算,服務端負責運算。這一小項目做起來很有意思,而且難度不大,所以推薦初學者試著去做做。下面分享在實現上述“計算機”的過程。

簡單的基於tcp協議的 C/S編程都離不開這幾個函數:

服務端:socket,bind,listen,accept,recv,send
用戶端:socket,connect,recv,send

 

因為“計算機”還設計涉及用戶端的阻塞(因為用戶端提交了運算要求過後,服務端可能要等會才能回送計算結果,這時要求用戶端阻塞等候),所以涉及select函數。select函數用途廣泛,很容易實現阻塞功能。介紹一個文檔,有興趣可以參考一下:http://wenku.baidu.com/view/0ea86ffdc8d376eeaeaa3198.html

客觀測試環境

可以在一個主機上同時進行服務端和用戶端的測試,只要客戶在connect的時候用迴環地址(或者本地靜態IP地址)串連服務端就可以。

實現細節

socket不成功怎麼辦,bind不成功怎麼辦,listen不成功怎麼辦...都有相應的出錯處理,編程過程中養成這種“考慮周細”的習慣(考慮所有的情況,比如出錯的時候列印錯誤資訊),對調試很有協助。

http://www.gnu.org/software/libc/manual/html_node/Internet-Address-Formats.html

— Data Type: struct sockaddr_in

This is the data type used to represent socket addresses in the Internet namespace. It has the following members:

sa_family_t sin_family
This identifies the address family or format of the socket address. You should store the value AF_INET in this member. See Socket Addresses.
struct in_addr sin_addr
This is the Internet address of the host machine. See Host Addresses, and Host Names, for how to get a value to store here.
unsigned short int sin_port
This is the port number. See Ports.

註:sockaddr_in此類型資料在使用之前請務必bzero

其中sin_addr是結構體,

http://www.gnu.org/software/libc/manual/html_node/Host-Address-Data-Type.html

— Data Type: struct in_addr

This data type is used in certain contexts to contain an IPv4 Internet host address. It has just one field, named s_addr, which records the host address number as an uint32_t.

inet_pton和inet—_ntop方便點分十進位IP地址字串和uint32_t(IP地址是4位元組,應為網路位元組序)的轉換。

select

如上所述要求,“因為用戶端提交了運算要求過後,服務端可能要等會才能回送計算結果,這時要求用戶端阻塞等候”,select經常扮演阻塞的角色。
http://www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html(文檔很詳細)
因此用戶端提交運算要求之後,需要將其socket讀功能阻塞,直到有資料(即服務端回送的結果)時才進行讀取。如果用輪詢的方法,很浪費CPU。

上實驗結果圖片解解饞

伺服器啟動

用戶端啟動,太快了,結果都出來了

伺服器處理結束,退出

計算機要求:客戶需要傳遞尾碼運算式簡單運算(如),伺服器直接運行就即可。
缺陷:此計算機只服務於一個客戶,其他不給予處理;此計算機進一步改進可以實現接受不只一個客戶的請求。

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 1024int 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    if((sockfd = initserver(SOCK_STREAM,(struct sockaddr *)&server,sizeof(server),1)) < 0)    {        printf("initserver error\n");        return 0;    }// if        printf("serving\n");//serve    serve(sockfd);    close(sockfd);    return 0;}

以上純屬筆者YY後的作品,還存在很多的缺陷與不足;拋磚引玉,與廣大朋友分享。歡迎創意建議提議。另,如有錯誤,歡迎斧正。

本文完 2012-08-02

搗亂小子 http://www.daoluan.net/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.