基于TCP的C/S初级网络编程1
导读
本篇实现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 anuint32_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相关推荐
- socket通信需要网线连接吗_从socket到TCP协议,透彻理解网络编程
进行程序开发的同学,无论Web前端开发.Web后端开发,还是搜索引擎和大数据,几乎所有的开发领域都会涉及到网络编程.比如我们进行Web服务端开发,除了Web协议本身依赖网络外,通常还需要连接数据库,而 ...
- day26-2 基于TCP协议的套接字编程
目录 基于TCP协议的套接字编程 套接字 套接字工作流程 基于TCP协议的套接字编程(简单) 服务端 客户端 基于TCP协议的套接字编程(循环) 服务端 客户端1 客户端2 基于TCP协议的套接字编程 ...
- TCP原理,Socket与网络编程入门
TCP原理,Socket与网络编程入门 开篇 从互联网的诞生以来,网络程序逐渐普及.计算机网络将各个计算机连接到一起使它们可以通信.在现代,网络已成为我们十分重要的一部分.这次不搞些费脑子的东西,就让 ...
- Android之使用TCP和URL协议进行网络编程
手机本身是作为手机终端使用的,因此它的计算能力,存储能力都是有限的.它的主要优势是携带方便,可以随时打开,而且手机通常总是处于联网状态.因此网络支持对于手机应用非常重要. Android完全支持JDK ...
- linux tcp客户端端口号,Linux网络编程--服务器客户端(TCP实现)
Linux下的一个服务器客户端的小程序,基于TCP的实现:服务器可以同时接受多个客户的接入,通过子进程处理客户请求,下面的例子中,服务器只将客户的IP和端口以及发送的信息显示,然后原样的将客户发送的信 ...
- 基于Linux下的服务器搭建(网络编程)
这是服务器,客户端是qt编写的.看情况再写吧 注意这是头文件: #include <stdio.h> #include <string.h> #include <stdl ...
- tcp udp区别优缺点_Linux网络编程面试题--tcp和udp的区别
(1)TCP是基于连接的,UDP是基于无连接的. (2)TCP的数据是可靠的,UDP的数据是不可靠的. (3)TCP的数据是有序的,UDP的数据是无序的. (4)TCP不保存用户边界,UDP保存用户边 ...
- tcp丢包率_网络编程 | TCP/IP基础知识
在2017年10月深圳 Cocos 沙龙上,有幸结识了社区中大名顶顶的Colin,Shawn在论坛上第一次看到Colin的团队用CocosCreator制作的<热血暗黑>时就被深深地震撼到 ...
- java socket 通信协议_java网络通信(基于TCP协议可靠通信的socket编程)
package cn.wang; import java.io.*; import java.net.*; public class Server { static int num = 1;//客户端 ...
最新文章
- android sendmessage和post的区别,handler中post和send方式区别
- (计算机组成原理)第二章数据的表示和运算-第二节9:本节习题
- 数据算法排序之归并排序
- goip技术原理图解_图解电工识图一看就懂
- 创建图书管理_阿拉尔市文化(图书)馆举办总分馆制建设图书管理软件、文化云专题培训班...
- python计算机入门_Python零基础入门(1)-------计算机基础
- Git简洁教程:本地项目如何与GitHub互连
- jquery的deferred使用详解
- NetScaler的cookieinsert和sourceip联合保持机制
- 一文带你看透手机号码归属地
- DedeCMS 栏目三级联动树形菜单的代码
- 解决Android图片剪切返回崩溃问题
- C++ 游戏开发(一)图形库EasyX的安装及测试
- 02-SpringBoot集成MinIo
- Linux 文件格式转码工具
- 点云分割训练哪家强?监督,弱监督,无监督还是半监督?
- LaTeX 段落:段落缩进、段落间距、行距
- 交通领域主要SCI期刊——2017年JCR
- 送给广大IT男同学的金句良言
- 产品经理培训课程:产品经理从专业走向管理