select tcp server 流程图
使用非阻塞I / O和select()的服务器
参考代码
https://www.ibm.com/docs/en/i/7.2?topic=designs-example-nonblocking-io-select
TCP socket建立
http://www.gnu.org/software/libc/manual/html_node/Inet-Example.html
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
int
make_socket (uint16_t port)
{
int sock;
struct sockaddr_in name;
/* Create the socket. */
sock = socket (PF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("socket");
exit (EXIT_FAILURE);
}
/* Give the socket a name. */
name.sin_family = AF_INET;
name.sin_port = htons (port);
name.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
{
perror ("bind");
exit (EXIT_FAILURE);
}
return sock;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void
init_sockaddr (struct sockaddr_in *name,
const char *hostname,
uint16_t port)
{
struct hostent *hostinfo;
name->sin_family = AF_INET;
name->sin_port = htons (port);
hostinfo = gethostbyname (hostname);
if (hostinfo == NULL)
{
fprintf (stderr, "Unknown host %s.\n", hostname);
exit (EXIT_FAILURE);
}
name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
}
设计tcp server
http://www.gnu.org/software/libc/manual/html_node/Server-Example.html
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 5555
#define MAXMSG 512
int
read_from_client (int filedes)
{
char buffer[MAXMSG];
int nbytes;
nbytes = read (filedes, buffer, MAXMSG);
if (nbytes < 0)
{
/* Read error. */
perror ("read");
exit (EXIT_FAILURE);
}
else if (nbytes == 0)
/* End-of-file. */
return -1;
else
{
/* Data read. */
fprintf (stderr, "Server: got message: `%s'\n", buffer);
return 0;
}
}
int
main (void)
{
extern int make_socket (uint16_t port);
int sock;
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in clientname;
size_t size;
/* Create the socket and set it up to accept connections. */
sock = make_socket (PORT);
if (listen (sock, 1) < 0)
{
perror ("listen");
exit (EXIT_FAILURE);
}
/* Initialize the set of active sockets. */
FD_ZERO (&active_fd_set);
FD_SET (sock, &active_fd_set);
while (1)
{
/* Block until input arrives on one or more active sockets. */
read_fd_set = active_fd_set;
if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0)
{
perror ("select");
exit (EXIT_FAILURE);
}
/* Service all the sockets with input pending. */
for (i = 0; i < FD_SETSIZE; ++i)
if (FD_ISSET (i, &read_fd_set))
{
if (i == sock)
{
/* Connection request on original socket. */
int new;
size = sizeof (clientname);
new = accept (sock,
(struct sockaddr *) &clientname,
&size);
if (new < 0)
{
perror ("accept");
exit (EXIT_FAILURE);
}
fprintf (stderr,
"Server: connect from host %s, port %hd.\n",
inet_ntoa (clientname.sin_addr),
ntohs (clientname.sin_port));
FD_SET (new, &active_fd_set);
}
else
{
/* Data arriving on an already-connected socket. */
if (read_from_client (i) < 0)
{
close (i);
FD_CLR (i, &active_fd_set);
}
}
}
}
}
tcp server 代码2
https://www.cs.cmu.edu/afs/cs/academic/class/15213-f99/www/class26/selectserver.c
/*
* selectserver.c - A TCP echo server that keeps track of the
* number of connection requests and allows
* the user to query this count and to terminate
* the server from stdin. It multiplexes two different
* kinds of events:
* 1. the user has hit the return key
* 2. a connection request has arrived
*
* usage: tcpserver <port>
*
* commands from stdin:
* "c<nl>" print the number of connection requests
* "q<nl>" quit the server
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
/*
* error - wrapper for perror
*/
void error(char *msg) {
perror(msg);
exit(1);
}
int main(int argc, char **argv) {
int parentfd; /* parent socket */
int childfd; /* child socket */
int portno; /* port to listen on */
int clientlen; /* byte size of client's address */
struct sockaddr_in serveraddr; /* server's addr */
struct sockaddr_in clientaddr; /* client addr */
char buf[BUFSIZE]; /* message buffer */
int optval; /* flag value for setsockopt */
int n; /* message byte size */
int connectcnt; /* number of connection requests */
int notdone;
fd_set readfds;
/*
* check command line arguments
*/
if (argc != 2) {
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(1);
}
portno = atoi(argv[1]);
/*
* socket: create the parent socket
*/
parentfd = socket(AF_INET, SOCK_STREAM, 0);
if (parentfd < 0)
error("ERROR opening socket");
/* setsockopt: Handy debugging trick that lets
* us rerun the server immediately after we kill it;
* otherwise we have to wait about 20 secs.
* Eliminates "ERROR on binding: Address already in use" error.
*/
optval = 1;
setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int));
/*
* build the server's Internet address
*/
bzero((char *) &serveraddr, sizeof(serveraddr));
/* this is an Internet address */
serveraddr.sin_family = AF_INET;
/* let the system figure out our IP address */
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
/* this is the port we will listen on */
serveraddr.sin_port = htons((unsigned short)portno);
/*
* bind: associate the parent socket with a port
*/
if (bind(parentfd, (struct sockaddr *) &serveraddr,
sizeof(serveraddr)) < 0)
error("ERROR on binding");
/*
* listen: make this socket ready to accept connection requests
*/
if (listen(parentfd, 5) < 0) /* allow 5 requests to queue up */
error("ERROR on listen");
/* initialize some things for the main loop */
clientlen = sizeof(clientaddr);
notdone = 1;
connectcnt = 0;
printf("server> ");
fflush(stdout);
/*
* main loop: wait for connection request or stdin command.
*
* If connection request, then echo input line
* and close connection.
* If command, then process command.
*/
while (notdone) {
/*
* select: Has the user typed something to stdin or
* has a connection request arrived?
*/
FD_ZERO(&readfds); /* initialize the fd set */
FD_SET(parentfd, &readfds); /* add socket fd */
FD_SET(0, &readfds); /* add stdin fd (0) */
if (select(parentfd+1, &readfds, 0, 0, 0) < 0) {
error("ERROR in select");
}
/* if the user has entered a command, process it */
if (FD_ISSET(0, &readfds)) {
fgets(buf, BUFSIZE, stdin);
switch (buf[0]) {
case 'c': /* print the connection cnt */
printf("Received %d connection requests so far.\n", connectcnt);
printf("server> ");
fflush(stdout);
break;
case 'q': /* terminate the server */
notdone = 0;
break;
default: /* bad input */
printf("ERROR: unknown command\n");
printf("server> ");
fflush(stdout);
}
}
/* if a connection request has arrived, process it */
if (FD_ISSET(parentfd, &readfds)) {
/*
* accept: wait for a connection request
*/
childfd = accept(parentfd,
(struct sockaddr *) &clientaddr, &clientlen);
if (childfd < 0)
error("ERROR on accept");
connectcnt++;
/*
* read: read input string from the client
*/
bzero(buf, BUFSIZE);
n = read(childfd, buf, BUFSIZE);
if (n < 0)
error("ERROR reading from socket");
/*
* write: echo the input string back to the client
*/
n = write(childfd, buf, strlen(buf));
if (n < 0)
error("ERROR writing to socket");
close(childfd);
}
}
/* clean up */
printf("Terminating server.\n");
close(parentfd);
exit(0);
}
普通TCP server代码3
https://gist.github.com/Alexey-N-Chernyshov/4634731
普通TCP server代码4
https://www.tenouk.com/Module41.html
设计web server
原理介绍
https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Introduction
https://www.slideshare.net/chienhungpan/micro-http-server-implemented-in-c-coscup-2016-65181546
阻塞型
https://dev-notes.eu/2018/06/http-server-in-c/
非阻塞
/fork()方法
https://github.com/taweisuode/webserver/blob/master/webserver/webserver.c
Lighttpd, Shttpd, mongoose, Thttpd, Boa, Mini_httpd, Appweb, Goahead
tinyhttpd
https://github.com/cbsheng/tinyhttpd
webnet
https://gitee.com/yejiashuai_admin/webnet
代码研究
https://www.ibm.com/docs/en/i/7.2?topic=designs-example-nonblocking-io-select
https://www.cs.cmu.edu/afs/cs/academic/class/15213-f99/www/class26/selectserver.c
http://www.gnu.org/software/libc/manual/html_node/Server-Example.html
https://www.geeksforgeeks.org/tcp-and-udp-server-using-select/