github 代码 地址
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 4096
#define SERV_PORT 9877
#define LISTENQ 1024
void str_echo(int sockfd);
void err_sys(const char *, ...);
// client interface
void str_cli(FILE *fp, int sockfd);
#include "unp.h"
#include
#include
#include
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);
}
#include "unp.h"
// maxline 4096
int 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 readable
if ((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));
}
}
}
#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;
}
}
}
}
}
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)