頭文件 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地址與端口號必須要和服務器一直。