Guide
This article introduces the "Calculator" of the C/S architecture.
After reading network programming, I am not conscious of YY: to implement a simple calculator, the client provides a simple operation, and the server is responsible for the operation. This small project is very interesting and difficult to do, so it is recommended that beginners try to do it. The following describes how to implement the "Calculator.
Simple TCP-based c/s programming is inseparable from these functions:
Server: socket, bind, listen, accept, Recv, send
Client: socket, connect, Recv, send
Because the "Calculator" is also designed to block the client (because the client may wait for the server to return the computing result after submitting the operation requirements, the client is required to block the wait), so the select function is involved. The select function is widely used and can easily implement blocking. Introduction to a document, interested can refer to: http://wenku.baidu.com/view/0ea86ffdc8d376eeaeaa3198.html
Objective test environment
You can test both the server and the client on a host, as long as the customer uses the loopback address (or local static IP address) to connect to the server during connect.
Implementation Details
What if socket fails, BIND fails, and listen fails... there are corresponding error handling, and this kind of habit of "taking into account weekly details" (taking into account all situations, such as printing error information when an error occurs) is very helpful for debugging.
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 shocould store the value
AF_INETIn 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.
Note: sockaddr_in this type of data must be bzero before use
Sin_addr is the struct,
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, nameds_addr, Which records the host address number asuint32_t.
Inet_ton and iNet-_ ntop can be easily converted into a decimal IP address string and uint32_t (the IP address is 4 bytes and should be in the network byte order.
Select
As stated above, "after the client submits the operation requirements, the server may have to wait for the result to be sent back. In this case, the client is required to block the wait." select is often used as a blocking role.
Http://www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html (detailed documentation)
Therefore, after the client submits an operation request, it must block its socket READ function until there is data (that is, the result returned by the server. If the round-robin method is used, CPU is a waste.
Solution
Server startup
The client was started. It was too fast and the results all came out.
Server processing is complete, quit
Calculator requirements: the customer needs to pass the suffix expression for simple operations (such as), the server can directly run.
Defect: This calculator serves only one customer and is not processed by others. Further improvements to this calculator can be made to accept requests from more than one customer.
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;}
The above is my work after YY, and there are still many defects and deficiencies. I will share it with my friends. You are welcome to propose creative suggestions. In addition, if there is any error, you are welcome to make an axe.
End of this article 2012-08-02
Spoof http://www.daoluan.net/