linux c语言tcp,我个人的Linux TCP server和client测试源码,C语言(2)(★firecat推荐★)...
1、直接上TCP Server源碼,這種方法沒有使用向muduo那樣的活塞式buffer,可謂簡單粗暴:
#include
#include
#include
#include
#include
#include
#include
#include /*setrlimit */
#include
#include
#include
#include
#include
#include
#include
#include
#define IPADDRESS "127.0.0.1"
#define PORT 8011
#define MAXSIZE 1024
#define LISTENQ 5
#define FDSIZE 50000
#define EPOLLEVENTS 100
int stop_server = 0;
//函數聲明
//創建套接字并進行綁定
static int socket_bind(const char* ip,int port);
//IO多路復用epoll
static void do_epoll(int listenfd);
//事件處理函數
static void handle_events(int epollfd,struct epoll_event *events,int num,int listenfd,char *buf);
//處理接收到的連接
static void handle_accpet(int epollfd,int listenfd);
//讀處理
static void do_read(int epollfd,int fd,char *buf);
//寫處理
static void do_write(int epollfd,int fd,char *buf);
//添加事件
static void add_event(int epollfd,int fd,int state);
//修改事件
static void modify_event(int epollfd,int fd,int state);
//刪除事件
static void delete_event(int epollfd,int fd,int state);
//other
static int do_error(int fd, int *error);
static int setnonblocking(int fd);
static void daemonize(void);
static int set_fdlimit();
static void signal_exit_handler();
static void signal_exit_func(int signo);
int main(int argc,char *argv[])
{
//設置每個進程允許打開的最大文件數,socket
if (set_fdlimit() < 0)
{
return -1;
}
int background = 0;
if (background)
{
daemonize();
}
//設置信號處理,SIG_IGN表示忽略信號,SIG_DFL表示使用信號的默認處理方式
//signal(SIGHUP, SIG_IGN); //開啟的話,就捕獲不到終端窗口關閉的信號了。即窗口關閉,進程仍然進行。
signal(SIGPIPE, SIG_IGN);
/*
if (argc != 2) {
fprintf(stderr, "Usage: %s port\n", argv[0]);
return 1;
}
int port = atoi(argv[1]);*/
int listenfd;
listenfd = socket_bind(IPADDRESS,PORT);
listen(listenfd,LISTENQ);
printf("start listening...\n");
signal_exit_handler();
do_epoll(listenfd);
return 0;
}
static int socket_bind(const char* ip,int port)
{
int listenfd;
struct sockaddr_in servaddr;
listenfd = socket(AF_INET,SOCK_STREAM,0);
if (listenfd == -1)
{
perror("socket error:");
exit(1);
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
//inet_pton(AF_INET,ip,&servaddr.sin_addr);
servaddr.sin_port = htons(port);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int error;
int reuse = 1;
int ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
if (ret == -1)
{
return do_error(listenfd, &error);
}
if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1)
{
perror("bind error: ");
exit(1);
}
return listenfd;
}
static void do_epoll(int listenfd)
{
int epollfd;
struct epoll_event events[EPOLLEVENTS];
int ret;
char buf[MAXSIZE];
memset(buf,0,MAXSIZE);
//創建一個描述符
int error;
epollfd = epoll_create(1024);//1024 is just a hint for the kernel
if (epollfd == -1)
{
return do_error(epollfd, &error);
}
//添加監聽描述符事件
add_event(epollfd,listenfd,EPOLLIN);
while ( stop_server == 0 )
{
//獲取已經準備好的描述符事件
ret = epoll_wait(epollfd,events,EPOLLEVENTS,-1);
handle_events(epollfd,events,ret,listenfd,buf);
}
close(epollfd);
}
static void handle_events(int epollfd,struct epoll_event *events,int num,int listenfd,char *buf)
{
int i;
int fd;
//進行選好遍歷
for (i = 0;i < num;i++)
{
fd = events[i].data.fd;
//根據描述符的類型和事件類型進行處理
if ((fd == listenfd) &&(events[i].events & EPOLLIN))
handle_accpet(epollfd,listenfd);
else if (events[i].events & EPOLLIN)
do_read(epollfd,fd,buf);
else if (events[i].events & EPOLLOUT)
do_write(epollfd,fd,buf);
}
}
static void handle_accpet(int epollfd,int listenfd)
{
int clifd;
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(cliaddr);
clifd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen);
if (clifd == -1)
perror("accpet error:");
else
{
printf("accept a new client: %s:%d\n",inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);
//添加一個客戶描述符和事件
add_event(epollfd,clifd,EPOLLIN);
}
}
static void do_read(int epollfd,int fd,char *buf)
{
int nread;
nread = read(fd,buf,MAXSIZE);
if (nread == -1)
{
perror("read error:");
close(fd);
delete_event(epollfd,fd,EPOLLIN);
}
else if (nread == 0)
{
fprintf(stderr,"client close,fd=%d\n",fd);
close(fd);
delete_event(epollfd,fd,EPOLLIN);
}
else
{
printf("read message is: %s,fd=%d\n",buf,fd);
//修改描述符對應的事件,由讀改為寫
modify_event(epollfd,fd,EPOLLOUT);
}
}
static void do_write(int epollfd,int fd,char *buf)
{
int nwrite;
nwrite = write(fd,buf,strlen(buf));
if (nwrite == -1)
{
perror("write error:");
close(fd);
delete_event(epollfd,fd,EPOLLOUT);
}
else
modify_event(epollfd,fd,EPOLLIN);
memset(buf,0,MAXSIZE);
}
static void add_event(int epollfd,int fd,int state)
{
struct epoll_event ev;
ev.events = state;
ev.data.fd = fd;
epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);
setnonblocking(fd);
}
static void delete_event(int epollfd,int fd,int state)
{
struct epoll_event ev;
ev.events = state;
ev.data.fd = fd;
epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&ev);
}
static void modify_event(int epollfd,int fd,int state)
{
struct epoll_event ev;
ev.events = state;
ev.data.fd = fd;
epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&ev);
}
static int do_error(int fd, int *error)
{
fprintf(stderr, "error: %s\n", strerror(errno));
*error = errno;
while ((close(fd) == -1) && (errno == EINTR));
errno = *error;
return 1;
}
static int setnonblocking(int fd)
{
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return old_option;
}
static void daemonize(void) { //come from /redis/server.c/daemonize()
int fd;
if (fork() != 0) exit(0); /* parent exits */
setsid(); /* create a new session */
/* Every output goes to /dev/null. If Redis is daemonized but
* the 'logfile' is set to 'stdout' in the configuration file
* it will not log at all. */
if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO) close(fd);
}
}
static int set_fdlimit()
{
//設置每個進程允許打開的最大文件數
//這項功能等價于linux終端命令 "ulimit -n 102400"
struct rlimit rt;
rt.rlim_max = rt.rlim_cur = FDSIZE;
if (setrlimit(RLIMIT_NOFILE, &rt) == -1)
{
perror("setrlimit error");
return -1;
}
return 0;
}
static void signal_exit_handler()
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_exit_func;
sigaction(SIGINT, &sa, NULL);//當按下ctrl+c時,它的效果就是發送SIGINT信號
sigaction(SIGTERM, &sa, NULL);//kill pid
sigaction(SIGQUIT, &sa, NULL);//ctrl+\代表退出SIGQUIT
//SIGSTOP和SIGKILL信號是不可捕獲的,所以下面兩句話寫了等于沒有寫
sigaction(SIGKILL, &sa, NULL);//kill -9 pid
sigaction(SIGSTOP, &sa, NULL);//ctrl+z代表停止
//#define SIGTERM 15
//#define SIGKILL 9
//kill和kill -9,兩個命令在linux中都有殺死進程的效果,然而兩命令的執行過程卻大有不同,在程序中如果用錯了,可能會造成莫名其妙的現象。
//執行kill pid命令,系統會發送一個SIGTERM信號給對應的程序。
//執行kill -9 pid命令,系統給對應程序發送的信號是SIGKILL,即exit。exit信號不會被系統阻塞,所以kill -9能順利殺掉進程。
}
static void signal_exit_func(int signo)
{
printf("exit signo is %d\n", signo);
stop_server = 1;
}
2、添加buffer和最小堆定時器的完整版本,請參見:
---
參考文章:
IO多路復用之epoll總結?--- 注意源碼有一處錯誤,需要修正為:
static void handle_accpet(int epollfd,int listenfd)
{
int clifd;
struct sockaddr_in cliaddr;
socklen_t? cliaddrlen = sizeof(cliaddr);
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的linux c语言tcp,我个人的Linux TCP server和client测试源码,C语言(2)(★firecat推荐★)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 个人住房商业贷款手续及流程
- 下一篇: linux 垃圾桶快捷键,Linux的基