您的位置:首页 > 运维架构 > Linux

简单的Client / Server 使用 linux 伯克利 socket实现

2012-05-29 20:04 876 查看
服务器:

/*
*run command:
*	g++ server.cpp -o server && ./server
*/

#ifndef SERVER
#define SERVER

#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<errno.h>
#include<assert.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include<signal.h>

const int SERVPORT = 5555;//服务器监听端口号
const int BACKLOG = 10; //最大同时连接请求数
const int MAX_DATA_SIZE = 1000;

const int MAX_NAME_LENGTH = 21;
const int MAX_PHONE_LENGTH = 15;
const int MAX_HOMEADDRESS_LENGTH = 61;

struct Address
{
char name[MAX_NAME_LENGTH];
char phone[MAX_PHONE_LENGTH];
char home_address[MAX_HOMEADDRESS_LENGTH];
int age;
};
//void insert_client_fd(int* client_list,int client_fd);
//void accept_client();
//void* interact_with_client(void* clients_list);
void* send_msg_to_client(int client_fd, char* msg);
void sig_int(int signo);
void generate_phone(char* phone);
void generate_name(char* name);
void generate_rand_n_address(int n);
bool find_phone_with_name(char* name, char* phone);
bool find_name_with_phone(char* phone, char* name);
bool write_address(Address** addresses, int n);
void print_addresses();
void handle_request(const int client_id, const char* buf);
void init();

void serv();
void client_add(int* client, int fd);
void client_del(int* client, int fd);

static char const* fileName = ".address";
//sock_fd:监听socket
static int sock_fd;
/*
* 读写锁
*/
pthread_rwlock_t rwlock;

int main(int argc, char* argv[])
{
init();
//accept_client();
serv();
return 0;
}
/*
* 初始化
*/
void init()
{
if (signal(SIGINT, sig_int) == SIG_ERR)
{
perror("signal(SIGINT,sig_int)");
}
if (signal(SIGQUIT, sig_int) == SIG_ERR)
{
perror("signal(SIGQUIT,sig_int)");
}

srand(time(0));
print_addresses();
//每次随机产生10个
//generate_rand_n_address(10);
}

void serv()
{
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket创建出错");
_exit(1);
}

//本地地址信息
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(SERVPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;////INADDR_ANY;inet_addr(serverIP);//
printf("%s\n", inet_ntoa(my_addr.sin_addr));
bzero(&(my_addr.sin_zero), 8);

printf("before bind\n");
if (bind(sock_fd, (struct sockaddr*) &my_addr, sizeof(my_addr)) == -1)
{
perror("bind出错!");
exit(1);
}
printf("before listen\n");
if (listen(sock_fd, BACKLOG) == -1)
{
perror("listen出错");
exit(1);
}

int client[BACKLOG + 1];
memset(client, -1, sizeof(int) * (BACKLOG + 1));

/*
* 最大的fd
*/
int maxfd;
fd_set rset, allset;
FD_ZERO(&allset);

FD_SET(sock_fd,&allset);
maxfd = sock_fd;

for (;;)
{
rset = allset;
if (select(maxfd + 1, &rset, NULL, NULL, NULL) < 0)
{
perror("select error");
}

//client_fd:数据传输socket
int client_fd;
char buf[MAX_DATA_SIZE];

//监听fd 准备好了
if (FD_ISSET(sock_fd,&rset))
{
//客户端地址信息
struct sockaddr_in remote_addr;
socklen_t sin_size;
sin_size = sizeof(struct sockaddr_in);
printf("before accept\n");
if ((client_fd = accept(sock_fd, (struct sockaddr*) &remote_addr,
&sin_size)) == -1)
{
perror("accept出错\n");
continue;
}

client_add(client, client_fd);
FD_SET(client_fd,&allset);
//调整maxfd
if(client_fd>maxfd)
maxfd=client_fd;

printf("received a connection from %s assigned fd=%d\n", inet_ntoa(
remote_addr.sin_addr), client_fd);

if (vfork() == 0)
{
//服务程序:子进程
//完成发送消息后,退出
char buf[MAX_DATA_SIZE];
sprintf(buf, "Hello,Your Number is %d", client_fd);
send_msg_to_client(client_fd, buf);
exit(0);
}
}
//有客户端发来请求
for (int i = 0; i <= BACKLOG; i++)
{
client_fd = client[i];
//printf("client[%d]=%d\n",i,client_fd);
//client_fd有请求
if (client_fd > 0 && FD_ISSET(client_fd,&rset))
{
int receivebytes = recv(client_fd, buf, MAX_DATA_SIZE, 0);
if(receivebytes<0)
{
perror("recv error!");
}
else if(receivebytes==0)
{
FD_CLR(client_fd,&allset);
client_del(client,client_fd);
close(client_fd);
}
else
{
buf[receivebytes] = '\0';
printf("received cmd from %d:%s\n", client_fd, buf);
if (strncmp(buf, "quit", 4) == 0)
{
FD_CLR(client_fd,&allset);
client_del(client,client_fd);
close(client_fd);
printf("client_fd id=%lu quit\n", client_fd);
}
else
handle_request(client_fd, buf);
}
}//if (client_fd > 0 && FD_ISSET(client_fd,&rset))
}//for (int i = 0; i <= maxfd; i++)
}
}
void client_add(int* client, int fd)
{
for (int i = 0; i <= BACKLOG; i++)
{
if (client[i] == -1)
{
client[i] = fd;
break;//居然两次,都忘记了break,编程水平太低了...
}
}
}
void client_del(int* client, int fd)
{
for (int i = 0; i <= BACKLOG; i++)
{
if (client[i] == fd)
client[i] = -1;
}
}

void handle_request(const int client_id, const char* buf)
{
char* helpString = "help #显示可用的命令\n"
"list #显示通讯录所有内容(假设没有重名)\n"
"name TheNameString#查询手机号\n"
"phon ThePhoneNumberString#phone 查询名字\n"
"shel #本地shell \n"
"quit #quit\n"
"inse #insert 暂时不实现\n";
if (strncmp(buf, "help", 4) == 0)
{
send_msg_to_client(client_id, helpString);
}
else if (strncmp(buf, "list", 4) == 0)
{

FILE* fp = fopen(fileName, "r");
if (fp == NULL)
{
perror("fopen error!");
return;
}
else
{
Address addr;
char buf[MAX_DATA_SIZE];
int count = 1;
while (fread(&addr, sizeof(Address), 1, fp) == 1)
{
sprintf(buf, "%-5dname:'%s',phone=%s,home_address=%s,age:%d\n",
count, addr.name, addr.phone, addr.home_address,
addr.age);
//一次发送一条记录
send_msg_to_client(client_id, buf);
count++;
}
}
fclose(fp);

}
else if (strncmp(buf, "name", 4) == 0)
{
char name[MAX_NAME_LENGTH];
strcpy(name, buf + 5);
printf("name=%s\n", name);
char phone[MAX_PHONE_LENGTH];
phone[0] = '\0';
find_phone_with_name(name, phone);
char buf[MAX_DATA_SIZE];
if (strlen(phone) > 0)
{
sprintf(buf, "phone=%s\n", phone);
}
else
{
sprintf(buf, "No such Name=%s\n", name);
}
send_msg_to_client(client_id, buf);
}
else if (strncmp(buf, "phon", 4) == 0)
{
char phone[MAX_PHONE_LENGTH];
strcpy(phone, buf + 5);
printf("phone=%s\n", phone);
char name[MAX_NAME_LENGTH];
name[0] = '\0';
find_name_with_phone(name, phone);
char buf[MAX_DATA_SIZE];
if (strlen(name) > 0)
{
sprintf(buf, "name=%s\n", name);
}
else
{
sprintf(buf, "No such Phone Number=%s\n", phone);
}
send_msg_to_client(client_id, buf);
}
/*
* 在线程中,不可以放在handle_request中处理
* (还没有找到原因)
*/
else
{
char temp[MAX_DATA_SIZE];
sprintf(temp, "Unknow Command:%s\n\ttry help\n", buf);
send_msg_to_client(client_id, temp);
}
}
/*
* 保证SIGINT,SIGQUIT,可以正常关闭连接
*/
void sig_int(int signo)
{
printf("\nclose(%d)\nexit\n", sock_fd);
close(sock_fd);
_exit(0);
}

/*
* 发送消息到client_fd
*/
void* send_msg_to_client(int client_fd, char* msg)
{
assert(msg!=NULL);

if (send(client_fd, msg, strlen(msg), 0) == -1)
{
perror("send出错\n");
}
return NULL;
}

/*
* 随机产生 n 项
*/
void generate_rand_n_address(int n)
{
Address** addresses = (Address**) malloc(sizeof(Address*) * n);

for (int i = 0; i < n; i++)
{
addresses[i] = (Address*) malloc(sizeof(Address));
generate_name(addresses[i]->name);
generate_phone(addresses[i]->phone);
addresses[i]->age = rand() % 100 + 10;
printf("generate:name->%s\tphone->%s\tage=%d\n", addresses[i]->name,
addresses[i]->phone, addresses[i]->age);
}
write_address(addresses, n);
//释放空间
for (int i = 0; i < n; i++)
free(addresses[i]);
free(addresses);
}
/*
* 将数组addresses,n个address写入文件
*/
bool write_address(Address* addresses[], int n)
{

FILE* fp = fopen(fileName, "a");
if (fp == NULL)
{
perror("fopen error!\n");
exit(1);
}
else
{
for (int i = 0; i < n; i++)
if (fwrite(addresses[i], sizeof(Address), 1, fp) < 0)
{
perror("fwrite error!\n");
exit(1);
}
}
fclose(fp);
return 1;
}

/*
* 查找name 用电话号码 phone
*/
bool find_name_with_phone(char* name, char* phone)
{
assert(name!=NULL);
assert(phone!=NULL);

FILE* fp = fopen(fileName, "r");
if (fp == NULL)
{
perror("fopen error!\n");
return 0;
}
else
{
Address addr;
while (fread((char*) &addr, sizeof(Address), 1, fp) == 1)
{
if (strcmp(addr.phone, phone) == 0)
{
strcpy(name, addr.name);
return 1;
}
}
}

return 0;
}
/*
* 重名的 返回文件中第一个名字的phone
* 成功则,phone是结果并返回1,否则返回0,phone不变
*/
bool find_phone_with_name(char* name, char* phone)
{
assert(name!=NULL);
assert(phone!=NULL);

FILE* fp = fopen(fileName, "r");
if (fp == NULL)
{
perror("fopen error!\n");
return 0;
}
else
{
Address addr;
while (fread((char*) &addr, sizeof(Address), 1, fp) == 1)
{
if (strcmp(addr.name, name) == 0)
{
strcpy(phone, addr.phone);
return 1;
}
}
}

return 0;
}
/*
* 将文件(若有)的所有通讯录输出到标准输出
*/
void print_addresses()
{

FILE* fp = fopen(fileName, "r");
if (fp == NULL)
{
perror("fopen error!");
return;
}
else
{
Address addr;
int count = 1;
while (fread(&addr, sizeof(Address), 1, fp) == 1)
{
printf("%-5dname:'%s',phone=%s,home_address=%s,age:%d\n", count,
addr.name, addr.phone, addr.home_address, addr.age);
count++;
}
}
fclose(fp);

}

/*
* 随机生成一个字符串 长度小于 MAX_NAME_LENGTH
*/
char* alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
void generate_name(char* name)
{
int len = rand() % MAX_NAME_LENGTH;
if (len < 5)
{
len += 5;
}
for (int i = 0; i < len; i++)
{
name[i] = alphabet[rand() % (sizeof(alphabet))];
}
name[len] = '\0';
}

/*
* 产生11位的电话号码
*/
char* number = "0123456789";
void generate_phone(char* phone)
{
phone[0] = '1';
for (int i = 1; i < 11; i++)
{
phone[i] = number[rand() % 10];
}
phone[11] = '\0';//末尾
}

#endif //


客户端:

/*
* run command
*		g++ client.cpp -o client && ./client 192.168.111.139#serverIP
*/

#ifndef CLIENT
#define CLIENT
#include<sys/select.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<unistd.h>
#include<pthread.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<signal.h>
#include<sys/socket.h>

const int SERVPORT = 5555;
const int MAX_DATA_SIZE = 1000;//每次最大数据传输量

//void* send_msg_to_server(void* args);
void* interact_with_server(void* agrs);
void sig_int(int signo);

static int sockfd = -1;

int main(int argc, char* argv[])
{
if (signal(SIGINT, sig_int) == SIG_ERR)
{
perror("signal(SIGINT,sig_int)");
}
if (signal(SIGQUIT, sig_int) == SIG_ERR)
{
perror("signal(SIGQUIT,sig_int)");
}

if (argc < 2)
{
printf("请输入server IP\n");
exit(1);
}
char* serverIP = argv[1];
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERVPORT);
serv_addr.sin_addr.s_addr = inet_addr(serverIP);//*((struct in_addr*)host->h_addr);
printf("serverIP:%s\n", inet_ntoa(serv_addr.sin_addr));
bzero(&(serv_addr.sin_zero), 8);

int recvbytes;
char buf[MAX_DATA_SIZE];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket创建出错!");
exit(1);
}
if (connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
{
perror("connect出错!");
sleep(1);
}

if (sockfd < 0)
{
return NULL;
}

//用于select
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(sockfd,&readSet);
//FD_SET(STDIN_FILENO,&readSet);

int reseivebytes;
//char buf[MAX_DATA_SIZE];
while (1)
{
fd_set readSet_temp;
readSet_temp = readSet;
//一次使用 1s接收数据
timeval tvptr;
tvptr.tv_sec = 1;
tvptr.tv_usec = 0;

bool flag_recived = 0;
int rs;
while ((rs = select(sockfd + 1, &readSet_temp, NULL, NULL, &tvptr)) > 0)
{
flag_recived = 1;
//recv准备好了
if ((reseivebytes = recv(sockfd, buf, MAX_DATA_SIZE, 0)) == -1)
{
perror("recv 错误!\n");
exit(1);
}
else if (reseivebytes > 0)
{
buf[reseivebytes] = '\0';
printf("received msg from server:\n%s\n", buf);
}
else if (reseivebytes < 0)
{
//连接已断开
printf("close(%d)\n", sockfd);
close(sockfd);
return NULL;
}
memset(buf, 0, MAX_DATA_SIZE);

//readSet_temp还原
readSet_temp = readSet;
}
if (rs < 0)
{
perror("select!");
}
/*
*没有recv不必输出提示信息
*/
//if(flag_recived==1)
printf("input cmd sended to server-->");
/*
* 读入一行(包含末尾的'\n'),去除'\n'='\0'
*/
fgets(buf, MAX_DATA_SIZE, stdin);
/*
* 空行不发送
*/
if (strlen(buf) > 1)
{
buf[strlen(buf) - 1] = '\0';
if (strncmp(buf, "shel", 4) == 0)
{
system(buf + 5);
}
else if (send(sockfd, buf, strlen(buf), 0) == -1)
{
perror("send 出错!\n");
}

if (strncmp(buf, "quit", 4) == 0)
{
close(sockfd);
exit(0);
}
}
}
close(sockfd);
return 0;
}
void sig_int(int signo)
{
printf("\nclose(%d)\n", sockfd);
close(sockfd);
_exit(0);
}

#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: