【并发服务器系列】1 停等模型
we'll create a concurrent server program with some kind of message handling functions.
But first, let's look at some easy example. Then step by step , we create more and more complex programs.
chat.h
#ifndef __CHAT_H
#define __CHAT_H
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
//for inet_pton
#include <arpa/inet.h>
//for waitpid
#include <sys/types.h>
#include <sys/wait.h>
#define SA struct sockaddr
#define SERVER_PORT 54321
#define PROTOL_TYPE 0xE3
#define OP_MESSAGE 0x4E
const short MAX_MSG_LENGTH = 512;
struct Message_Head
{
char protol_type;
char msg_type ;
size_t msg_length;
int msg_size;
//this sort will make the msg lager than it should
Message_Head()
{
protol_type = PROTOL_TYPE;
msg_type = OP_MESSAGE;
msg_length = 0;
msg_size = 3;//?
};
};
struct Message
{
Message_Head msg_head;
char msg_content[MAX_MSG_LENGTH];
Message()
{
memset(msg_content, 0, sizeof(msg_content) );
};
};
#define __CHAT_H
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
//for inet_pton
#include <arpa/inet.h>
//for waitpid
#include <sys/types.h>
#include <sys/wait.h>
#define SA struct sockaddr
#define SERVER_PORT 54321
#define PROTOL_TYPE 0xE3
#define OP_MESSAGE 0x4E
const short MAX_MSG_LENGTH = 512;
struct Message_Head
{
char protol_type;
char msg_type ;
size_t msg_length;
int msg_size;
//this sort will make the msg lager than it should
Message_Head()
{
protol_type = PROTOL_TYPE;
msg_type = OP_MESSAGE;
msg_length = 0;
msg_size = 3;//?
};
};
struct Message
{
Message_Head msg_head;
char msg_content[MAX_MSG_LENGTH];
Message()
{
memset(msg_content, 0, sizeof(msg_content) );
};
};
my_sock_api.cpp
#include "chat.h"
#define LISTENQ 10
int sock_init(int &sockfd ,struct sockaddr_in &servaddr, uint16_t server_port)
{
sockfd = 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(server_port);
return sockfd;
}
int sock_server_init(int &listenfd , uint16_t server_port)
{
struct sockaddr_in servaddr;
sock_init(listenfd, servaddr , server_port);
if(bind(listenfd, (SA*)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind");
return -1;
}
listen(listenfd, LISTENQ);
return listenfd;
}
int sock_client_init(const char*ipaddress, uint16_t server_port)
{
int sockfd ;
struct sockaddr_in servaddr;
sock_init(sockfd, servaddr, server_port);
inet_pton(AF_INET, ipaddress, &servaddr.sin_addr);
if(0 != connect(sockfd, (SA *) &servaddr, sizeof(servaddr)))
{
perror("connect");
return -1;
}
return sockfd;
#define LISTENQ 10
int sock_init(int &sockfd ,struct sockaddr_in &servaddr, uint16_t server_port)
{
sockfd = 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(server_port);
return sockfd;
}
int sock_server_init(int &listenfd , uint16_t server_port)
{
struct sockaddr_in servaddr;
sock_init(listenfd, servaddr , server_port);
if(bind(listenfd, (SA*)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind");
return -1;
}
listen(listenfd, LISTENQ);
return listenfd;
}
int sock_client_init(const char*ipaddress, uint16_t server_port)
{
int sockfd ;
struct sockaddr_in servaddr;
sock_init(sockfd, servaddr, server_port);
inet_pton(AF_INET, ipaddress, &servaddr.sin_addr);
if(0 != connect(sockfd, (SA *) &servaddr, sizeof(servaddr)))
{
perror("connect");
return -1;
}
return sockfd;
chat_server.cpp
#include "chat.h"
int listenfd, connfd;
extern int sock_server_init(int &listenfd , uint16_t server_port);
void err_sys(const char *error_string)
{
printf("%s\n", error_string);
}
extern void p_read_from_p(int clientfd);
extern int p_write_to_p(int clientfd, const char *msg);
void sig_chld(int signo)
{
pid_t pid;
int stat;
while( (pid = waitpid(-1, &stat, WNOHANG)) > 0 )
{
printf("client %d terminated \n", pid);
}
return;
}
void chat_server()
{
printf("chat server start\n");
void sig_chld(int);
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr ;
if(sock_server_init(listenfd,(uint16_t) SERVER_PORT) < 0)
{
return ;
}
signal(SIGCHLD, sig_chld);
char buf[200] = {0};
for(;;)
{
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd, (SA*)&cliaddr, &clilen )) < 0)
{
if(errno == EINTR)
continue;
else
err_sys("accept error");
}
printf("incoming connection from IP: %s Port: %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, buf, sizeof(buf)),
ntohs(cliaddr.sin_port));
p_read_from_p(connfd);
p_write_to_p(connfd, "hi , this is server");
close(connfd);
}//for
int listenfd, connfd;
extern int sock_server_init(int &listenfd , uint16_t server_port);
void err_sys(const char *error_string)
{
printf("%s\n", error_string);
}
extern void p_read_from_p(int clientfd);
extern int p_write_to_p(int clientfd, const char *msg);
void sig_chld(int signo)
{
pid_t pid;
int stat;
while( (pid = waitpid(-1, &stat, WNOHANG)) > 0 )
{
printf("client %d terminated \n", pid);
}
return;
}
void chat_server()
{
printf("chat server start\n");
void sig_chld(int);
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr ;
if(sock_server_init(listenfd,(uint16_t) SERVER_PORT) < 0)
{
return ;
}
signal(SIGCHLD, sig_chld);
char buf[200] = {0};
for(;;)
{
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd, (SA*)&cliaddr, &clilen )) < 0)
{
if(errno == EINTR)
continue;
else
err_sys("accept error");
}
printf("incoming connection from IP: %s Port: %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, buf, sizeof(buf)),
ntohs(cliaddr.sin_port));
p_read_from_p(connfd);
p_write_to_p(connfd, "hi , this is server");
close(connfd);
}//for
clientProcesser.cpp
#include "chat.h"
void p_read_from_p(int clientfd)
{
if(0 == clientfd)
return ;
Message msg_receive;
int read_size = 0;//fd read_size
if(( read_size = read(clientfd, &msg_receive.msg_head, sizeof(msg_receive.msg_head))) == 0)
{
return;//connection closed by other end
}
if(( read_size = read(clientfd, &msg_receive.msg_content, msg_receive.msg_head.msg_length)) == 0)
{
return;//connection closed by other end
}
printf(" ----> receive msg_content:\t %s \n", msg_receive.msg_content);
fflush(stdout);
}
int p_write_to_p(int clientfd, const char *msg)
{
size_t slen = strlen(msg);
if(slen > MAX_MSG_LENGTH || 0 == slen)
return -1;
Message msg_send;
msg_send.msg_head.msg_length = slen;
strncpy(msg_send.msg_content , msg, slen);
int wn = write(clientfd, &msg_send ,sizeof(msg_send.msg_head)+slen );
printf(" write finished msg:\t %s \n",msg );
void p_read_from_p(int clientfd)
{
if(0 == clientfd)
return ;
Message msg_receive;
int read_size = 0;//fd read_size
if(( read_size = read(clientfd, &msg_receive.msg_head, sizeof(msg_receive.msg_head))) == 0)
{
return;//connection closed by other end
}
if(( read_size = read(clientfd, &msg_receive.msg_content, msg_receive.msg_head.msg_length)) == 0)
{
return;//connection closed by other end
}
printf(" ----> receive msg_content:\t %s \n", msg_receive.msg_content);
fflush(stdout);
}
int p_write_to_p(int clientfd, const char *msg)
{
size_t slen = strlen(msg);
if(slen > MAX_MSG_LENGTH || 0 == slen)
return -1;
Message msg_send;
msg_send.msg_head.msg_length = slen;
strncpy(msg_send.msg_content , msg, slen);
int wn = write(clientfd, &msg_send ,sizeof(msg_send.msg_head)+slen );
printf(" write finished msg:\t %s \n",msg );
chat_client.cpp
#include "chat.h"
extern int sock_client_init(const char*ipaddress, uint16_t server_port);
extern int p_write_to_p(int clientfd, const char *msg);
extern void p_read_from_p(int clientfd);
void chat_client(const char* linkin_ip)
{
printf("chat client start %s \n", linkin_ip);
int clientfd = sock_client_init(linkin_ip, SERVER_PORT);
if(clientfd < 0 )
{
return ;
}
p_write_to_p(clientfd, "hello, this is client");
p_read_from_p(clientfd);
extern int sock_client_init(const char*ipaddress, uint16_t server_port);
extern int p_write_to_p(int clientfd, const char *msg);
extern void p_read_from_p(int clientfd);
void chat_client(const char* linkin_ip)
{
printf("chat client start %s \n", linkin_ip);
int clientfd = sock_client_init(linkin_ip, SERVER_PORT);
if(clientfd < 0 )
{
return ;
}
p_write_to_p(clientfd, "hello, this is client");
p_read_from_p(clientfd);
chatmain.cpp
#include "chat.h"
void usage()
{
printf("./chat& \t first chat login , in order to receive other client's message \n\
./chat endpoint_ip_address \t start a client to chat with endpoint_ip_address \n");
}
extern void chat_server();
extern void chat_client(const char *linkin_ip);
int main(int argc, char **argv)
{
if(argc == 1)
{
chat_server();
}
else if(argc == 2)
{
chat_client(argv[1]);
}
else
{
usage();
}
return 0;
}
void usage()
{
printf("./chat& \t first chat login , in order to receive other client's message \n\
./chat endpoint_ip_address \t start a client to chat with endpoint_ip_address \n");
}
extern void chat_server();
extern void chat_client(const char *linkin_ip);
int main(int argc, char **argv)
{
if(argc == 1)
{
chat_server();
}
else if(argc == 2)
{
chat_client(argv[1]);
}
else
{
usage();
}
return 0;
}
g++ chatmain.cpp chat_server.cpp chat_client.cpp my_sock_api.cpp clientProcesser.cpp -o chat