#include<myhead.h>
#define ERR(msg) do{\
fprintf(stderr, "__%d__:", __LINE__);\
perror(msg);\
}while(0);
#define PORT 1314
#define IP "192.168.114.56"
int stdin_put()
{
ssize_t ret = 0;
char buf[128] = "";
bzero(buf, sizeof(buf));
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf) - 1] = 0;
//加\n是为了刷新缓冲区
printf("%s\n", buf);
return 0;
}
int Cli_connect(int sfd, struct sockaddr_in Cli_addr[], fd_set* preadfds, int* pmaxfd)
{
int newfd = -1;
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
if(newfd < 0)
{
ERR("accept()");
return -1;
}
printf("[%s:%d]客户端连接成功 newfd=%d\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
Cli_addr[newfd] = cin;
FD_SET(newfd, preadfds);
*pmaxfd = *pmaxfd>newfd ? *pmaxfd : newfd;
return 0;
}
int Cli_intreact(int fd, struct sockaddr_in Cli_addr[], fd_set* preadfds, int* pmaxfd)
{
char buf[128] = "";
bzero(buf, sizeof(buf));
//接收
ssize_t res = recv(fd, buf, sizeof(buf), 0);
if(res < 0)
{
ERR("recv()");
return -1;
}
else if(0 == res)
{
printf("[%s:%d]客户端下线 newfd=%d\n", inet_ntoa(Cli_addr[fd].sin_addr), ntohs(Cli_addr[fd].sin_port), fd);
//关闭文件描述符
close(fd);
FD_CLR(fd, preadfds);
while(FD_ISSET(*pmaxfd, preadfds) == 0 && (*pmaxfd)-- >= 0);
return 0;
}
printf("[%s:%d] newfd=%d : %s\n", inet_ntoa(Cli_addr[fd].sin_addr), ntohs(Cli_addr[fd].sin_port), fd, buf);
//发送
strcat(buf, "*_*");
if(send(fd, buf, sizeof(buf), 0) < 0)
{
ERR("send()");
return -1;
}
printf("发送成功\n");
return 0;
}
int main(int argc, const char *argv[])
{
//创建套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd < 0)
{
ERR("socket()");
exit(1);
}
printf("socket success sfd=%d\n", sfd);
//允许端口被快速复用成功
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
ERR("setsockopt()");
exit(1);
}
printf("允许端口被快速复用成功\n");
//绑定套接字
struct sockaddr_in sin = {AF_INET, htons(PORT), .sin_addr.s_addr = inet_addr(IP)};
socklen_t addrlen = sizeof(sin);
if(bind(sfd, (struct sockaddr*)&sin, addrlen) < 0)
{
ERR("bind()");
exit(1);
}
printf("bind success\n");
//设置为监听状态
if(listen(sfd, 128) < 0)
{
ERR("listen()");
exit(1);
}
printf("listen success\n");
//创建一个读集合
fd_set readfds, tempfds;
FD_ZERO(&readfds);
FD_SET(0, &readfds);
FD_SET(sfd, &readfds);
int maxfd = sfd;
struct sockaddr_in Cli_addr[1024];
int fds;
while(1)
{
tempfds = readfds;
//执行IO多路复用
fds = select(maxfd+1, &tempfds, NULL, NULL, NULL);
if(fds < 0)
{
ERR("select()");
exit(1);
}
for(int fd=0; fd<=maxfd; fd++)
{
if(FD_ISSET(fd, &tempfds) == 0)
continue;
if(0 == fd)
{
//触发终端输入事件
printf("触发终端输入事件\n");
stdin_put();
}
else if(sfd == fd)
{
//触发客户端连接事件
printf("触发客户端连接事件\n");
Cli_connect(sfd, Cli_addr, &readfds, &maxfd);
}
else
{
//触发客户端交互事件
printf("触发客户端交互事件\n");
Cli_intreact(fd, Cli_addr, &readfds, &maxfd);
}
}
}
if(close(sfd) < 0)
{
ERR("close()");
exit(1);
}
return 0;
}
高级IO多路复用select简单创建TCP服务器
最新推荐文章于 2024-10-16 21:57:42 发布