头文件 utili.h
#pragma once #include<stdio.h> #include<unistd.h> #include<string.h> #include<stdlib.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<pthread.h> #define BUFFER_SIZE 256 #define TCP 0 #define UDP 1 #define LISTW_QUEUE_SIZE 5 typedef enum {QUIT,ADD,SUB,MUL,DIV,MOD}OPER_ENUM; typedef struct oper_st { int op1; int op2; OPER_ENUM op; }oper_st; int start_up(char *ip,short port , int mode) { int sockfd; if(mode == TCP) { sockfd = socket(AF_INET,SOCK_STREAM,0); } else if(mode == UDP) { sockfd = socket(AF_INET,SOCK_DGRAM,0); } else { printf("mode errror,mode is must tcp or udp.....\n"); return -1; } struct sockaddr_in address; address.sin_family = AF_INET; address.sin_port = htons(port); address.sin_addr.s_addr = inet_addr(ip); socklen_t addrlen = sizeof(struct sockaddr); int yes = 1; setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes , sizeof(int)); int ret = bind(sockfd,(struct sockaddr*)&address,addrlen); if(ret == -1) { perror("bind"); return -1; } if(mode == TCP) { ret = listen(sockfd,LISTW_QUEUE_SIZE); if(ret == -1) { perror("listen"); return -1; } } return sockfd; }
ser.cpp
服务器启动是需要两个参数 :ip地址与端口号 ,服务器菜单控制 1:显示已经连接的客户端数 2:显示已经连接的客户端ip地址与端口号 0:退出
/********************* Creation Date:2018-05-06 09:13*******************/ #include"utili.h" #include<iostream> #include<stdlib.h> #include<string.h> using namespace std; #include<list> typedef struct client_node { char ip[16]; short port; }client_node; typedef struct client_info { int client_num; list<client_node*> lt; }client_info; static int client_num; void process_handler(int sockConn); void* Server_Seach(void *arg) { client_info *info = (client_info*)arg; int select = 1; while(1) { printf("*********************************\n"); printf("*[1]Search Client Num. *\n"); printf("*[2]Search Clint Info. *\n"); printf("*[0]Quit System. *\n"); printf("*********************************\n"); printf("Input Choice:>"); scanf("%d",&select); switch(select) { case 1: printf("client number:>%d\n",info->client_num); break; case 2: { list<client_node *>::iterator it = (info->lt).begin(); while(it != (info->lt).end()) { cout<<"****************************"<<endl; cout<<"*client ip:>"<<(*it)->ip<<endl; cout<<"*client port:>"<<(*it)->port<<endl; cout<<"****************************"<<endl; ++it; } } break; case 0: printf("This server is quit....\n"); exit(1); break;; exit(1); } } } int main(int argc , char *argv[]) { client_info client; client.client_num = 0; pthread_t tid;//创建后台处理程序,采用线程,数据可以共享 pthread_create(&tid,NULL,Server_Seach,&client); int sockSer = start_up(argv[1],atoi(argv[2]),TCP);//调用套接字启动函数 if(sockSer == -1) { perror("socket"); return -1; } oper_st oper;//定义一个操作数 int sockConn; socklen_t len = sizeof(struct sockaddr); struct sockaddr_in addrCli; while(1) { sockConn = accept(sockSer,(struct sockaddr*)&addrCli,&len); if(sockConn == -1) { printf("Accept Client connect Error.\n"); continue; } else { client.client_num ++; client_node *s = (client_node*)malloc(sizeof(client_node)); strcpy(s->ip,inet_ntoa(addrCli.sin_addr)); s->port = ntohs(addrCli.sin_port); client.lt.push_back(s); printf("\n"); printf("<==============Client================>\n"); printf("<===========ip = %s========>\n",inet_ntoa(addrCli.sin_addr)); printf("<===========port= %d>=============>\n",ntohs(addrCli.sin_port)); printf("<====================================>\n"); } pid_t pid = fork(); if(pid == 0)//子进程 { process_handler(sockConn); } else if(pid > 0)//父进程 { // int status; // wait(&status); close(sockConn); } else { perror("fock process"); } } close(sockSer); return 0; } void process_handler(int sockConn) { int result; int ret_byte_size; oper_st oper; while(1) { ret_byte_size = recv(sockConn,&oper,sizeof(oper),0); if(ret_byte_size < 0 ) { perror("redv data error."); continue; } if(oper.op == ADD) result = oper.op1 + oper.op2; else if(oper.op == SUB) result = oper.op1 - oper.op2; else if(oper.op == MUL) result = oper.op1 * oper.op2; else if(oper.op == DIV) result = oper.op1 / oper.op2; else if(oper.op == MOD) result = oper.op1 % oper.op2; else if(oper.op == QUIT) { printf("Client Quit.\n"); break; } ret_byte_size = send(sockConn , &result ,sizeof(result),0); if(ret_byte_size < 0) { perror("send data error."); continue; } } close(sockConn); }
cli.c
/********************* Creation Date:2018-05-05 13:00*******************/ #include"utili.h" int main(int arge , char*argv[]) { int sockCli = socket(AF_INET , SOCK_STREAM,0); if(sockCli == -1) { perror("socket"); exit(1); } struct sockaddr_in addrSer; addrSer.sin_family = AF_INET; addrSer.sin_port = htons(atoi(argv[2])); addrSer.sin_addr.s_addr = inet_addr(argv[1]); socklen_t len = sizeof(struct sockaddr); int ret = connect(sockCli,(struct sockaddr*)&addrSer,len); if(ret == -1) { perror("connect"); close(sockCli); exit(1); } else { printf("Connect is success.\n"); } oper_st oper; char cmd[5]; int result; int ret_byte_size; while(1) { printf("please chose cmd[add,sub,mul,div,mod,quit]\n"); printf("Input cmd:\n"); scanf("%s",cmd); //if(strcmp(cmd ,"quit") == 0) // break; if(strcmp(cmd,"add") == 0) oper.op = ADD; else if(strcmp(cmd,"sub") == 0) oper.op = SUB; else if(strcmp(cmd,"mul") == 0) oper.op = MUL; else if(strcmp(cmd,"div") == 0) oper.op = DIV; else if(strcmp(cmd,"mod") == 0) oper.op = MOD; else if(strcmp(cmd,"quit") == 0) { oper.op = QUIT; send(sockCli,&oper,sizeof(oper),0); break; } printf("Please input op1 and op2:>"); scanf("%d %d",&oper.op1,&oper.op2); ret_byte_size = send(sockCli , &oper ,sizeof(oper),0); if(ret_byte_size < 0) { perror("send data errro."); continue; } ret_byte_size = recv(sockCli ,&result , sizeof(result),0); if(ret_byte_size < 0) { perror("recv data error."); } printf("result = %d\n",result); } close(sockCli); printf("System Quit ....\n"); return 0; }
客户端启动也需要两个参数:ip地址与端口号必须要和服务器一直。