日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux c语言tcp,我个人的Linux TCP server和client测试源码,C语言(2)(★firecat推荐★)...

發布時間:2025/4/5 linux 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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推荐★)...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。