简单的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:数据传输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
相关推荐
本文将深入探讨“跨平台的socket库,windows-linux-socket”这一主题,旨在帮助开发者理解如何在Windows和Linux操作系统之间实现兼容的Socket编程。 首先,Socket是操作系统提供的一种接口,用于在网络中进行进程间...
为了实现多人聊天,我们需要创建一个服务器端(Server)和多个客户端(Client)。服务器端需要监听来自多个客户端的连接请求,这就涉及到`listen()`函数,它使Socket进入监听状态。当有新的连接请求时,服务器调用`...
本文主要探讨如何在Linux环境中利用Berkeley Socket实现TCP/IP协议的实时通信。 首先,Socket是由伯克利大学的研究团队在80年代开发的,它被移植到UNIX操作系统中,形成了所谓的Berkeley Socket,为不同进程或站点...
标题"socket-windows-and-linux.zip_Linux windows socket_linux c++ sock"表明了本主题涉及的是跨平台的Socket编程,主要关注Linux和Windows操作系统下,使用C++语言实现的Socket接口。描述提到"利用socket函数实现...
在Linux中,Socket API是通过伯克利套接字(Berkeley Sockets)实现的,这是一个广泛使用的接口,支持多种网络协议,如TCP(传输控制协议)和UDP(用户数据报协议)。 1. **TCP Socket编程**:TCP是一种面向连接的...
在C语言中,我们通常使用伯克利套接字(BSD Socket)API来实现Socket编程。该API源于BSD操作系统,现在广泛应用于各种操作系统,包括Linux和Windows。 创建Socket首先需要调用`socket()`函数,它返回一个描述符,...
在Linux操作系统中,Socket是一种进程间通信机制,它允许不同进程或者网络间的进程进行通信。在本主题"Linux Socket程序设计源代码"中,我们将会深入探讨如何在Linux环境下编写客户端和服务器端的Socket程序。 首先...
伯克利socket编程 Socket编程基础本章以Berkeley Socket为主,主要介绍网络编程时常用的调用和程序使用它们的方法及基本结构。
在Linux操作系统中,Socket编程是实现网络通信的核心技术。它为进程间通信(IPC)提供了通用接口,使得不同网络协议的应用程序能够交换数据。本文将深入探讨Linux下的Socket编程,结合提供的资源,如"Linux框架图....
1. **套接字API**:在Linux中,Socket API是基于伯克利套接字(Berkeley Sockets)模型的,提供了一系列函数,如`socket()`, `bind()`, `listen()`, `accept()`, `connect()`, `send()`, `recv()`等,用于创建、配置...
在C语言中,我们通常使用伯克利套接字API(Berkeley Sockets API)来实现Socket编程。 1. **创建Socket**: 在VS2008中,我们需要包含`winsock2.h`头文件,并初始化Winsock库。通过调用`WSAStartup()`函数,我们...
在Linux下,socket接口遵循伯克利套接字(Berkeley Sockets)API。TraceRoute的实现需要创建一个UDP socket,因为Traceroute利用了UDP的特性——无连接和不保证数据传输。 2. **ICMP协议与TTL超时**:Traceroute...
“socket windows DEMO”进一步说明这是一个关于Windows环境下的Socket编程示例,可能包含了一个简单的服务器(socket_server.cpp)和客户端(socket_client.cpp)程序。服务器端通常会监听特定的端口,等待客户端的...
在Linux下,Sockets是通过伯克利套接字API(Berkeley Sockets API)来实现的,这是一个标准的接口,广泛用于各种网络编程。 1. **服务器端(SERVER端)**: - **创建Socket**:首先,服务器端需要创建一个Socket,...
在C++中实现SOCKET编程,通常需要包含`<winsock2.h>`或`<sys/socket.h>`头文件,使用Winsock库(Windows)或伯克利套接字API(Unix-like系统)。基本步骤包括初始化(`WSAStartup`),创建套接字(`socket`),绑定...
Linux操作系统中的Socket通信机制是网络编程中的核心组件,它提供了进程间通过网络进行通信的接口。Socket已经成为多种操作系统网络API的基础,特别是在Linux环境下,无论是基于TCP还是UDP的Socket通信技术都备受...
在C++中,通常使用伯克利套接字(Berkeley Sockets)接口来实现Socket编程。 1. **TCP/IP协议**:TCP(Transmission Control Protocol)是一种面向连接的、可靠的传输层协议,而IP(Internet Protocol)是无连接的...
Socket接口最初是在伯克利软件发布版(BSD)Unix中实现的,因此通常被称为“BSD Socket”。一个Socket描述了一个通信连接的一端,每个参与通信的程序都需要一个Socket来描述其通信端点。不同的主机可以通过各自的...
可以通过调用`fcntl()`函数或使用`setsockopt()`函数设置SOCKET的非阻塞选项来实现这一功能。 #### 八、Cisco IOS for S/390与BSD UNIX的区别 尽管Cisco IOS for S/390支持大部分BSD Sockets的功能,但在某些细节...