文章目录
代码仓库地址
Socket服务器设计
对于使用socket的网络服务器端程序,有两种常见的设计方式:
- 迭代式:服务器每次只处理一个客户端,只有当完全处理完一个客户端的请求后才会去处理下一个客户端
- 并发型:能够同时处理单个客户端的请求
实现迭代型的echo服务器
#include <syslog.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "sys_tem.h"
//< 创建迭代型 echo 服务器
#define BD_NO_CHDIR 01 /* Don't chdir("/") */
#define BD_NO_CLOSE_FILES 02 /* Don't close all open files */
#define BD_NO_REOPEN_STD_FDS 04 /* Don't reopen stdin, stdout, and
stderr to /dev/null */
#define BD_NO_UMASK0 010 /* Don't do a umask(0) */
#define BD_MAX_CLOSE 8192 /* Maximum file descriptors to close if
sysconf(_SC_OPEN_MAX) is indeterminate */
int becomeDaemon(int flags);
//< 调用会使一个程序变成守护进程
int becomeDaemon(int flags)
{
int maxfd, fd;
switch (fork()) { /* Become background process */
case -1: return -1;
case 0: break; /* Child falls through... */
default: _exit(EXIT_SUCCESS); /* while parent terminates */
}
if (setsid() == -1) /* Become leader of new session */
return -1;
switch (fork()) { /* Ensure we are not session leader */
case -1: return -1;
case 0: break;
default: _exit(EXIT_SUCCESS);
}
if (!(flags & BD_NO_UMASK0))
umask(0); /* Clear file mode creation mask */
if (!(flags & BD_NO_CHDIR))
chdir("/"); /* Change to root directory */
if (!(flags & BD_NO_CLOSE_FILES)) { /* Close all open files */
maxfd = sysconf(_SC_OPEN_MAX);
if (maxfd == -1) /* Limit is indeterminate... */
maxfd = BD_MAX_CLOSE; /* so take a guess */
for (fd = 0; fd < maxfd; fd++)
close(fd);
}
if (!(flags & BD_NO_REOPEN_STD_FDS)) {
close(STDIN_FILENO); /* Reopen standard fd's to /dev/null */
fd = open("/dev/null", O_RDWR);
if (fd != STDIN_FILENO) /* 'fd' should be 0 */
return -1;
if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO)
return -1;
if (dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO)
return -1;
}
return 0;
}
#define SERVICE "echo"
#define BUF_SIZE 500
#define IS_ADDR_STR_LEN 4096
int main(int argc, char *argv[])
{
int sfd;
ssize_t numRead;
socklen_t len;
struct sockaddr_storage claddr;
char buf[BUF_SIZE];
char addrStr[IS_ADDR_STR_LEN];
//< 将该进程变成守护进程
if (becomeDaemon(0) == -1)
perror("becomeDaemon");
//< 创建一个socket 成功返回 0 失败返回-1
sfd = inetBind(SERVICE, SOCK_DGRAM, NULL);
if (sfd == -1) {
//< 创建socket失败,记录一下日志
syslog(LOG_ERR, "Could not create server socket (%s)", strerror(errno));
exit(EXIT_FAILURE);
}
/* Receive datagrams and return copies to senders */
//< 收到之后,数收到的数据进行处理,并将原始数据回显的方式给发送者
for (;;) {
len = sizeof(struct sockaddr_storage);
numRead = recvfrom(sfd, buf, BUF_SIZE, 0,
(struct sockaddr *) &claddr, &len);
if (numRead == -1)
perror("recvfrom");
if (sendto(sfd, buf, numRead, 0, (struct sockaddr *) &claddr, len)
!= numRead)
syslog(LOG_WARNING, "Error echoing response to %s (%s)",
inetAddressStr((struct sockaddr *) &claddr, len,
addrStr, IS_ADDR_STR_LEN),
strerror(errno));
}
}