github 代码 地址
- unp.h
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/select.h>#define MAXLINE 4096
#define SERV_PORT 9877
#define LISTENQ 1024void str_echo(int sockfd);
void err_sys(const char *, ...);// client interface
void str_cli(FILE *fp, int sockfd);
- echo_client.c
#include "unp.h"
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>int main(int argc, char **argv) {int sockfd[5];struct sockaddr_in servaddr;int i=0;for (i=0; i<5; i++) {sockfd[i] = socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);connect(sockfd[i], (struct sockaddr*)&servaddr, sizeof(servaddr));}str_cli(stdin, sockfd[0]);exit(0);
}
- str_cli.c
#include "unp.h"// maxline 4096int max(int a, int b) {return a>b? a : b;
}void str_cli(FILE *fp, int sockfd) {int maxfdp1, stdineof;fd_set rset;char sendline[MAXLINE], receline[MAXLINE];int n;stdineof = 0;FD_ZERO(&rset);for (; ;) {// fileno 将标准 I/O 文件指针转换为对应的描述符if (stdineof == 0) {FD_SET(fileno(fp), &rset);}FD_SET(sockfd, &rset);maxfdp1 = max(fileno(fp), sockfd) + 1;select(maxfdp1, &rset, NULL, NULL, NULL);// 如果服务挂掉,客户端可以接受到消息,并退出if (FD_ISSET(sockfd, &rset)) { // socket is readableif ((n = read(sockfd, receline, MAXLINE)) == 0) {if (stdineof == 1) {return;} else {printf("str_cli: server terminated prematurely");return;}}write(fileno(stdout), receline, strlen(receline));bzero(receline, strlen(receline));}if (FD_ISSET(fileno(fp), &rset)) {if ( (n = read(fileno(stdin), sendline, MAXLINE) == 0) ){stdineof = 1;shutdown(sockfd, SHUT_WR);FD_CLR(fileno(fp), &rset);continue;}write(sockfd, sendline, strlen(sendline));bzero(sendline, strlen(sendline));}}
}
- echo_service.c
#include "unp.h"int main(int argc, char **argv) {int i, maxi, maxfd, listenfd, connfd, sockfd;int nready, client[FD_SETSIZE];size_t n;fd_set rset, allset;char buf[MAXLINE];socklen_t clilen;struct sockaddr_in cliaddr, servaddr;listenfd = socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));listen(listenfd, LISTENQ);maxfd = listenfd;maxi = -1; // client 数组当前使用项的最大下标for(i=0; i<FD_SETSIZE; i++) {client[i] = -1;}FD_ZERO(&allset);FD_SET(listenfd, &allset);for(;;) {rset = allset;nready = select(maxfd+1, &rset, NULL, NULL, NULL);if(FD_ISSET(listenfd, &rset)) {clilen = sizeof(cliaddr);connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);for (i=0; i<FD_SETSIZE; i++) {if (client[i] < 0 ) {client[i] = connfd;break;}}if (i == FD_SETSIZE) {exit(0);}FD_SET(connfd, &allset);if (connfd > maxfd) {maxfd = connfd;}if (i > maxi) {maxi = i;}if (--nready <= 0) {continue;}}for (i = 0; i <= maxi; i++) {if ((sockfd = client[i]) < 0) {continue;}if (FD_ISSET(sockfd, &rset)) {if ( ( n = read(sockfd, buf, MAXLINE)) == 0) {close(sockfd);FD_CLR(sockfd, &allset);client[i] = -1;} else {write(sockfd, buf, n);}if (--nready <= 0) {break;}}}}
}
- CMakeList.txt
project(echo_srv)
set(CMAKE_CXX_STANDARD 11)
add_executable(echo_srv echo_service.c error.c)# client
add_executable(echo_cli echo_client.c str_cli.c)