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

服务器:

/**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:数据传输socketint 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);//调整maxfdif(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);}elsehandle_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;}//用于selectfd_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



转载于:https://www.cnblogs.com/fengjunfeng/archive/2012/05/29/2797778.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/475131.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 261. 以图判树(全部连通+边数=V-1)

文章目录1. 题目2. 解题1. 题目 给定从 0 到 n-1 标号的 n 个结点&#xff0c;和一个无向边列表&#xff08;每条边以结点对来表示&#xff09;&#xff0c; 请编写一个函数用来判断这些边是否能够形成一个合法有效的树结构。 示例 1&#xff1a; 输入: n 5, 边列表 edges …

oracle自增自删分区的脚本,oracle实现自增方法(错误ora-04098解决)

mysql实现自增很简单&#xff0c;在主键处加上auto_increment关键字就可以了&#xff0c;而oracle实现起来并不是这么容易的&#xff0c;需要借助序列和触发器才能实现。具体代码如下&#xff1a;1.建立一个表&#xff1a;create table 户口本 (户号 INTEGER not null,户别 CHA…

php实现数字滚动效果,vue如何实现数字滚动增加效果?代码示例

项目中需要做数字滚动增加的效果&#xff0c;一开始很懵&#xff0c;研究了一下原理&#xff0c;发现很简单&#xff0c;贴出来分享一下 ^_^数字滚动组件&#xff1a;0props: {time: {type: Number,default: 2},value: {type: Number,default: 720000}},methods: {numberGrow (…

LeetCode 1061. 按字典序排列最小的等效字符串(并查集)

文章目录1. 题目2. 解题1. 题目 给出长度相同的两个字符串&#xff1a;A 和 B&#xff0c;其中 A[i] 和 B[i] 是一组等价字符。 举个例子&#xff0c;如果 A "abc" 且 B "cde"&#xff0c;那么就有 a c, b d, c e。 等价字符遵循任何等价关系的一般…

SheevaPlug是什么,有什么用途

简单说 SheevaPlug 是由 ARM CPU加上 Linux 作业系统的小型计算机, 用一个手掌就可以托住其中 CPU 是 1.2GHz 主频, 512MB DDR2, 512MB NAND Flash, 1个 USB口以及1个外接 SD 卡槽这个小计算机瑞安装了 linux 2.6.x 以及 debian 5.0 文件系统,拿到这个 sheevaplug 后你可以自行…

导出oracle表中数据,从Oracle中导出数据表!

C:\Documents and Settings\Administrator>expExport: Release 9.2.0.1.0 - Production on 星期四 12月 7 12:52:05 2006Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.用户名: peam口令:连接到: Oracle9i Enterprise Edition Release 9.2.0.1.0 - …

LeetCode 366. 寻找二叉树的叶子节点(上下翻转二叉树+BFS)

文章目录1. 题目2. 解题1. 题目 给你一棵二叉树&#xff0c;请按以下要求的顺序收集它的全部节点&#xff1a; 依次从左到右&#xff0c;每次收集并删除所有的叶子节点重复如上过程直到整棵树为空 示例: 输入: [1,2,3,4,5]1/ \2 3/ \ 4 5 输出: [[4,5,3],[2],[1]…

白话地图投影之初识地球

本文是Koala带你进入GIS世界的开篇&#xff0c;Koala打算用简单通俗的语言为大家介绍地图投影&#xff0c;帮助GISer理解地图投影的概念。作为进入GIS世界多年的老鸟&#xff0c;Koala也是在不断的实战中才真正理解和掌握地图投影的奥秘。 我们生活的地球长啥模样&#xff1f; …

oracle聚合函数wmsys,oracle 自定义聚合函数

oracle提供了聚合函数的API可以让我们方便的自己定义聚合函数。详细看oracle官方文档&#xff1a;http://docs.oracle.com/cd/B14117_01/appdev.101/b10800/dciaggref.htmhttp://docs.oracle.com/cd/B14117_01/appdev.101/b10800/dciaggfns.htm#g1008306wmsys.wm_concat(合并行…

欧洲杯2012

----------------------------------------------------------------------------- 欧洲杯2012 ----------------------------------------------------------------------------- 下载地址&#xff1a;http://itunes.apple.com/cn/app/ou-zhou-bei2012/id531622806?mt8 系统要…

LeetCode 245. 最短单词距离 III

文章目录1. 题目2. 解题1. 题目 给定一个单词列表和两个单词 word1 和 word2&#xff0c;返回列表中这两个单词之间的最短距离。 word1 和 word2 是有可能相同的&#xff0c;并且它们将分别表示为列表中两个独立的单词。 示例: 假设 words ["practice", "ma…

oracle 汇总上面所有,Oracle经验技巧汇总

Oracle经验技巧汇总对于Oracle学习者来说&#xff0c;掌握一些经验技巧是很有必要的&#xff0c;下面就和小编一起来学习学习吧!1.删除表空间DROP TABLESPACE TableSpaceName [INCLUDING CONTENTS [AND DATAFILES]]2.删除用户DROP USER User_Name CASCADE3.删除表的注意事项在删…

think in java - 第一章 学习笔记

总观第一章&#xff0c;作者试图为我们讲述面向对象编程&#xff08;oop&#xff09;的核心思想&#xff0c;而我的见解是&#xff0c;对象是对具体事物的一种抽象&#xff0c;对象与对象直接的关系通过消息联系。 关于类的三大特性&#xff1a;继承&#xff0c;多态&#xff0…

LeetCode 484. 寻找排列(找规律+贪心)

文章目录1. 题目2. 解题1. 题目 现在给定一个只由字符 ‘D’ 和 ‘I’ 组成的 秘密签名。 ‘D’ 表示两个数字间的递减关系&#xff0c;‘I’ 表示两个数字间的递增关系。 并且 秘密签名 是由一个特定的整数数组生成的&#xff0c;该数组唯一地包含 1 到 n 中所有不同的数字&a…

php将文件夹压缩成zip文件,将文件夹压缩成zip文件的php代码_php实例

1.请先下载我准备好的zip.php工具类&#xff0c;下载后解压&#xff0c;将里面的文件放入对应的目录中&#xff0c;我是放在虚拟目录下的include文件夹中。2.在你的php文件中加入下面代码即可复制代码 代码如下:require_once "./include/zip.php";$zip new PHPZip()…

LeetCode 651. 4键键盘(DP,Ctrl+CV)

文章目录1. 题目2. 解题1. 题目 假设你有一个特殊的键盘包含下面的按键&#xff1a; Key 1: (A)&#xff1a;在屏幕上打印一个 A。Key 2: (Ctrl-A)&#xff1a;选中整个屏幕。Key 3: (Ctrl-C)&#xff1a;复制选中区域到缓冲区。Key 4: (Ctrl-V)&#xff1a;将缓冲区内容输出…

stl algorithm -- sort ,unique

在写私信群聊代码的时候碰到怎么把一个vector<Int> 元素unique化的问题&#xff0c;基本上就是需要下面这么做&#xff0c;用<algorithm>中的&#xff0c;先sort再unique 1 #include <algorithm>2 #include <iostream>3 #include <vector>4 #inc…

oracle scn隐藏参数,Oracle隐含参数scn不一致启动

Oracle隐含参数&#xff1a;allow_resetlogs_corruption的使用提示&#xff1a;Oracle的隐含参数只应该在测试环境或者在Oracle Support的支持下使用orOracle隐含参数&#xff1a;allow_resetlogs_corruption的使用提示&#xff1a;Oracle的隐含参数只应该在测试环境或者在Orac…

LeetCode 298. 二叉树最长连续序列(自顶向下)

文章目录1. 题目2. 解题1. 题目 给你一棵指定的二叉树&#xff0c;请你计算它最长连续序列路径的长度。 该路径&#xff0c;可以是从某个初始结点到树中任意结点&#xff0c;通过「父 - 子」关系连接而产生的任意路径。 这个最长连续的路径&#xff0c;必须从父结点到子结点…

LeetCode 159. 至多包含两个不同字符的最长子串(滑动窗口)

文章目录1. 题目2. 解题1. 题目 给定一个字符串 s &#xff0c;找出 至多 包含两个不同字符的最长子串 t &#xff0c;并返回该子串的长度。 示例 1: 输入: "eceba" 输出: 3 解释: t 是 "ece"&#xff0c;长度为3。示例 2: 输入: "ccaabbb" 输…