导读

本篇实现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;}// ifif(nsec <= MAXSLEEP/2)//    delaysleep(nsec);}// for:return 0;
}int main(int argc,char * argv[])
{if(argc != 4){printf("you must input 4 arg\n");return 1;}// ifint 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 addrbzero(&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 databzero(buf,sizeof(buf));sprintf(buf,"%c%c%c",argv[1][0],argv[2][0],argv[3][0]);//connectif(connect_retry(fd,(struct sockaddr *)&server,sizeof(server)) < 0){printf("connect error\n");return 1;}// if//sendif(send(fd,buf,20,0) < 0) {printf("client send error\n");return 1;}// if//selectfd_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//recvbzero(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;}// ifprintf("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}// ifprintf("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);//recvprintf("accepted\n");bzero(buf,sizeof(buf));recv(clfd,buf,20,0);printf("recived\n");//calculatea = 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;}// switchsprintf(bufret,"the result:%d",ret);//sendprintf("sending\n");if(send(clfd,bufret,20,0) < 0){printf("server send error\n");return -1;}// ifprintf("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 serverif((sockfd = initserver(SOCK_STREAM,(struct sockaddr *)&server,sizeof(server),1)) < 0){printf("initserver error\n");return 0;}// ifprintf("serving\n");//serveserve(sockfd);close(sockfd);return 0;
}

以上纯属笔者YY后的作品,还存在很多的缺陷与不足;抛砖引玉,与广大朋友分享。欢迎创意建议提议。另,如有错误,欢迎斧正。

本文完 2012-08-02

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

转载于:https://www.cnblogs.com/daoluanxiaozi/archive/2012/08/02/2620686.html

基于TCP的C/S初级网络编程1相关推荐

  1. socket通信需要网线连接吗_从socket到TCP协议,透彻理解网络编程

    进行程序开发的同学,无论Web前端开发.Web后端开发,还是搜索引擎和大数据,几乎所有的开发领域都会涉及到网络编程.比如我们进行Web服务端开发,除了Web协议本身依赖网络外,通常还需要连接数据库,而 ...

  2. day26-2 基于TCP协议的套接字编程

    目录 基于TCP协议的套接字编程 套接字 套接字工作流程 基于TCP协议的套接字编程(简单) 服务端 客户端 基于TCP协议的套接字编程(循环) 服务端 客户端1 客户端2 基于TCP协议的套接字编程 ...

  3. TCP原理,Socket与网络编程入门

    TCP原理,Socket与网络编程入门 开篇 从互联网的诞生以来,网络程序逐渐普及.计算机网络将各个计算机连接到一起使它们可以通信.在现代,网络已成为我们十分重要的一部分.这次不搞些费脑子的东西,就让 ...

  4. Android之使用TCP和URL协议进行网络编程

    手机本身是作为手机终端使用的,因此它的计算能力,存储能力都是有限的.它的主要优势是携带方便,可以随时打开,而且手机通常总是处于联网状态.因此网络支持对于手机应用非常重要. Android完全支持JDK ...

  5. linux tcp客户端端口号,Linux网络编程--服务器客户端(TCP实现)

    Linux下的一个服务器客户端的小程序,基于TCP的实现:服务器可以同时接受多个客户的接入,通过子进程处理客户请求,下面的例子中,服务器只将客户的IP和端口以及发送的信息显示,然后原样的将客户发送的信 ...

  6. 基于Linux下的服务器搭建(网络编程)

    这是服务器,客户端是qt编写的.看情况再写吧 注意这是头文件: #include <stdio.h> #include <string.h> #include <stdl ...

  7. tcp udp区别优缺点_Linux网络编程面试题--tcp和udp的区别

    (1)TCP是基于连接的,UDP是基于无连接的. (2)TCP的数据是可靠的,UDP的数据是不可靠的. (3)TCP的数据是有序的,UDP的数据是无序的. (4)TCP不保存用户边界,UDP保存用户边 ...

  8. tcp丢包率_网络编程 | TCP/IP基础知识

    在2017年10月深圳 Cocos 沙龙上,有幸结识了社区中大名顶顶的Colin,Shawn在论坛上第一次看到Colin的团队用CocosCreator制作的<热血暗黑>时就被深深地震撼到 ...

  9. java socket 通信协议_java网络通信(基于TCP协议可靠通信的socket编程)

    package cn.wang; import java.io.*; import java.net.*; public class Server { static int num = 1;//客户端 ...

最新文章

  1. android sendmessage和post的区别,handler中post和send方式区别
  2. (计算机组成原理)第二章数据的表示和运算-第二节9:本节习题
  3. 数据算法排序之归并排序
  4. goip技术原理图解_图解电工识图一看就懂
  5. 创建图书管理_阿拉尔市文化(图书)馆举办总分馆制建设图书管理软件、文化云专题培训班...
  6. python计算机入门_Python零基础入门(1)-------计算机基础
  7. Git简洁教程:本地项目如何与GitHub互连
  8. jquery的deferred使用详解
  9. NetScaler的cookieinsert和sourceip联合保持机制
  10. 一文带你看透手机号码归属地
  11. DedeCMS 栏目三级联动树形菜单的代码
  12. 解决Android图片剪切返回崩溃问题
  13. C++ 游戏开发(一)图形库EasyX的安装及测试
  14. 02-SpringBoot集成MinIo
  15. Linux 文件格式转码工具
  16. 点云分割训练哪家强?监督,弱监督,无监督还是半监督?
  17. LaTeX 段落:段落缩进、段落间距、行距
  18. 交通领域主要SCI期刊——2017年JCR
  19. 送给广大IT男同学的金句良言
  20. 产品经理培训课程:产品经理从专业走向管理

热门文章

  1. Mybatis集成日志与ehcache
  2. 运维小白死磕的专业术语,你真的理解透了吗?
  3. 【博客美化】09.评论带头像,且支持旋转
  4. 面试题 01.09. 字符串轮转
  5. Python中利用*打印不同的三角形
  6. c语言交换两个变量的值 讲课,用C语言的泛型实现交换两个变量值
  7. php导入导出xls表,TP5.0 PHPExcel 数据表格导出导入
  8. linux 局域网内互ping丢包_ping命令还能这么用?
  9. 深度学习可解释性资料整合
  10. Crust Network将于1月14日12点开始暂停HTTP版本应用