tcp管理多客户端

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <arpa/inet.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <unistd.h>

#include <fcntl.h>

#include <errno.h>

#include <sys/time.h>

 

#define DEFAULT_PORT    21221    //默认端口

#define BUFF_SIZE       1024    //buffer大小

#define SELECT_TIMEOUT  5       //select的timeout seconds

 

//函数:设置sock为non-blocking mode

void setSockNonBlock(int sock) {

int flags;

flags = fcntl(sock, F_GETFL, 0);

if (flags < 0) {

perror("fcntl(F_GETFL) failed");

exit(EXIT_FAILURE);

}

if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {

perror("fcntl(F_SETFL) failed");

exit(EXIT_FAILURE);

}

}

 

//函数:更新maxfd

int updateMaxfd(fd_set fds, int maxfd) {

int i;

int new_maxfd = 0;

for (i = 0; i <= maxfd; i++) {

if (FD_ISSET(i, &fds) && i > new_maxfd) {

new_maxfd = i;

}

}

return new_maxfd;

}

 

int main(int argc, char *argv[]) {

unsigned short int port;

 

//获取自定义端口

if (argc == 2) {

port = atoi(argv[1]);

} else if (argc < 2) {

port = DEFAULT_PORT;

} else {

fprintf(stderr, "USAGE: %s [port]\n", argv[0]);

exit(EXIT_FAILURE);

}

 

//创建socket

int sock;

if ( (sock = socket(PF_INET, SOCK_STREAM, 0)) == -1 ) {

perror("socket failed, ");

exit(EXIT_FAILURE);

}

printf("socket done\n");

 

//in case of 'address already in use' error message

int yes = 1;

if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))) {

perror("setsockopt failed");

exit(EXIT_FAILURE);

}

 

//设置sock为non-blocking

setSockNonBlock(sock);

 

//创建要bind的socket address

struct sockaddr_in bind_addr;

memset(&bind_addr, 0, sizeof(bind_addr));

bind_addr.sin_family = AF_INET;

bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //设置接受任意地址

bind_addr.sin_port = htons(port);               //将host byte order转换为network byte order

 

//bind sock到创建的socket address上

if ( bind(sock, (struct sockaddr *) &bind_addr, sizeof(bind_addr)) == -1 ) {

perror("bind failed, ");

exit(EXIT_FAILURE);

}

printf("bind done\n");

 

//listen

if ( listen(sock, 5) == -1) {

perror("listen failed.");

exit(EXIT_FAILURE);

}

printf("listen done\n");

 

//创建并初始化select需要的参数(这里仅监视read),并把sock添加到fd_set中

fd_set readfds;

fd_set readfds_bak; //backup for readfds(由于每次select之后会更新readfds,因此需要backup)

struct timeval timeout;

int maxfd;

maxfd = sock;

FD_ZERO(&readfds);

FD_ZERO(&readfds_bak);

FD_SET(sock, &readfds_bak);

 

//循环接受client请求

int new_sock;

struct sockaddr_in client_addr;

socklen_t client_addr_len;

char client_ip_str[INET_ADDRSTRLEN];

int res;

int i;

char buffer[BUFF_SIZE];

int recv_size;

 

while (1) {

 

//注意select之后readfds和timeout的值都会被修改,因此每次都进行重置

readfds = readfds_bak;

maxfd = updateMaxfd(readfds, maxfd);        //更新maxfd

timeout.tv_sec = SELECT_TIMEOUT;

timeout.tv_usec = 0;

printf("selecting maxfd=%d\n", maxfd);

 

//select(这里没有设置writefds和errorfds,如有需要可以设置)

res = select(maxfd + 1, &readfds, NULL, NULL, &timeout);

if (res == -1) {

perror("select failed");

exit(EXIT_FAILURE);

} else if (res == 0) {

fprintf(stderr, "no socket ready for read within %d secs\n", SELECT_TIMEOUT);

continue;

}

 

//检查每个socket,并进行读(如果是sock则accept)

for (i = 0; i <= maxfd; i++) {

if (!FD_ISSET(i, &readfds)) {

continue;

}

//可读的socket

if ( i == sock) {

//当前是server的socket,不进行读写而是accept新连接

client_addr_len = sizeof(client_addr);

new_sock = accept(sock, (struct sockaddr *) &client_addr, &client_addr_len);

if (new_sock == -1) {

perror("accept failed");

exit(EXIT_FAILURE);

}

if (!inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip_str, sizeof(client_ip_str))) {

perror("inet_ntop failed");

exit(EXIT_FAILURE);

}

printf("accept a client from: %s\n", client_ip_str);

//设置new_sock为non-blocking

setSockNonBlock(new_sock);

//把new_sock添加到select的侦听中

if (new_sock > maxfd) {

maxfd = new_sock;

}

FD_SET(new_sock, &readfds_bak);

} else {

//当前是client连接的socket,可以写(read from client)

memset(buffer, 0, sizeof(buffer));

if ( (recv_size = recv(i, buffer, sizeof(buffer), 0)) == -1 ) {

perror("recv failed");

exit(EXIT_FAILURE);

}

printf("recved from new_sock=%d : %s(%d length string)\n", i, buffer, recv_size);

//立即将收到的内容写回去,并关闭连接

if ( send(i, buffer, recv_size, 0) == -1 ) {

perror("send failed");

exit(EXIT_FAILURE);

}

printf("send to new_sock=%d done\n", i);

if ( close(i) == -1 ) {

perror("close failed");

exit(EXIT_FAILURE);

}

printf("close new_sock=%d done\n", i);

//将当前的socket从select的侦听中移除

FD_CLR(i, &readfds_bak);

}

}

}

 

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值