//TCP服务器端
#include <stdio.h> //printf
#include <arpa/inet.h> //inet_addr htons
#include <sys/types.h>
#include <sys/socket.h> //socket bind listen accept connect
#include <netinet/in.h> //sockaddr_in
#include <strings.h> //bzero
#include <unistd.h> //close
#include <stdlib.h> //exit
#include <string.h> //strcat
#include <sys/select.h>
#include <sys/time.h>
#define N 128
#define errlog(errmsg) do{perror(errmsg);\
printf("%s --> %s -->%d\n", __FILE__, __func__, __LINE__);\
exit(1);\
}while(0)
int main(int argc, const char *argv[])
{
int sockfd, acceptfd;
struct sockaddr_in serveraddr, clientaddr;
socklen_t addlen = sizeof(struct sockaddr);
char buf[N] = {0};
fd_set readfds, tempfds;;
int maxfd;
ssize_t bytes;
int i = 0;
//bzero memset
bzero(&serveraddr, sizeof(serveraddr));
bzero(&clientaddr, sizeof(serveraddr));
if(argc < 3) {
printf("argument is too less\n");
exit(1);
}
//第一步:创建套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
errlog("fail to socket");
}
printf("sockfd = %d\n", sockfd);
//第二步:填充网络信息结构体
//inet_addr:将点分十进制IP地址转化为网络能够识别的整型数据
//htons:将主机字节序转化为网络字节序
//atoi:将数字型字符串转化为整型数据
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
//第三步:绑定
if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
errlog("fail to bind");
}
//第四步:将套接字设置为监听模式
if(listen(sockfd, 10) < 0) {
errlog("fail to listen");
}
//使用select函数实现TCP并发服务器
//第一步:清空集合
FD_ZERO(&readfds);
//第二步:将需要的文件描述符添加到集合里面
FD_SET(sockfd, &readfds);
int ret;
maxfd = sockfd;
while(1) {
tempfds = readfds;
//第三步:调用函数,阻塞等待文件描述符准备就绪
if((ret = select(maxfd + 1, &tempfds, NULL, NULL, NULL)) < 0) {
errlog("fail to select");
}
//判断文件描述符是否在集合里面,若在,则执行相应的IO操作
for(i = 0; i < maxfd + 1; i++) {
if(FD_ISSET(i, &tempfds)) {
if(i == sockfd) {
//第五步:阻塞等待客户端的连接请求
if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addlen)) < 0) {
errlog("fail to accept");
}
printf("%s --> %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
printf("acceptfd = %d\n", acceptfd);
//将新产生的文件描述符添加到集合里面
FD_SET(acceptfd, &readfds);
maxfd = maxfd > acceptfd ? maxfd : acceptfd;
} else {
if((bytes = recv(i, buf, N, 0)) < 0) {
errlog("fail to recv");
} else {
if(strncmp(buf, "quit", 4) == 0) {
FD_CLR(i, &readfds);
close(i);
break;
} else {
printf("client >>> %s\n", buf);
strcat(buf, " *_*");
if(send(i, buf, N, 0) < 0) { //SIGPIPE
errlog("fail to send");
}
}
}
}
}
}
}
close(acceptfd);
close(sockfd);
return 0;
}