#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
struct fifo_data
{
char fifo_name[32];
char fifo_type[32];
char fifo_buff[1024];
unsigned long long data_len;
int ret;
};
struct msg_data
{
int data_size;
char name[16];
struct fifo_data myfifo;
char buffer[1024];
};
struct client_fd_sql{
int client_fd[50];
int last;
};
typedef struct client_info{
int client_fd;
char name[256];
char ip[16];
short port;
pthread_t tid;
struct client_info *next;
}client_info_node;
#define list_for_each(head, pos)\
for(pos=head->next; pos!=NULL; pos=pos->next)
static client_info_node *request_client_info_node(const client_info_node *info)
{
client_info_node *new_node;
new_node = malloc(sizeof(client_info_node));
if(new_node == NULL)
{
perror("申请客户端节点异常");
return NULL;
}
if(info != NULL)
*new_node = *info;
new_node->next = NULL;
return new_node;
}
static inline void insert_client_info_node_to_link_list(client_info_node *head, client_info_node *insert_node)
{
client_info_node *pos;
for(pos=head; pos->next != NULL; pos=pos->next);
pos->next = insert_node;
}
void *client_thread(void *arg)
{
int client_fd;
struct msg_data recv_msg;
ssize_t recv_size, send_size;
client_info_node *pos, *list_head = arg;
list_for_each(list_head, pos)
{
if(pthread_self() == pos->tid)
{
client_fd = pos->client_fd;
break;
}
}
while(1)
{
bzero(&recv_msg, sizeof(recv_msg));
recv_size = recv(client_fd, &recv_msg, sizeof(recv_msg), 0);
if(recv_size == -1)
{
perror("接受数据异常");
break;
}
else if(recv_size == 0)
{
break;
}
list_for_each(list_head, pos)
{
if(pos->client_fd == client_fd)
continue;
printf("转发数据给端口号为%hu\n", pos->port);
send_size = send( pos->client_fd, &recv_msg, sizeof(recv_msg), 0);
if(send_size == -1)
break;
}
printf("接收到来自与客户端%ld个字节的数据:%s\n", recv_size, recv_msg.buffer);
}
return NULL;
}
int main(void)
{
int skt_fd;
int retval;
client_info_node *list_head, *new_node;
client_info_node cache_client_info;
ssize_t recv_size, send_size;
list_head = request_client_info_node(NULL);
skt_fd = socket( AF_INET, SOCK_STREAM, 0);
if(skt_fd == -1)
{
perror("申请套接字失败");
return -1;
}
int sw = 1;
retval = setsockopt(skt_fd, SOL_SOCKET, SO_REUSEADDR, &sw, sizeof(sw));
struct sockaddr_in native_addr;
native_addr.sin_family = AF_INET;
native_addr.sin_port = htons(6666);
native_addr.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind( skt_fd, (struct sockaddr *)&native_addr, sizeof(native_addr));
if(retval == -1)
{
perror("绑定套接字地址失败");
goto bind_socket_err;
}
retval = listen(skt_fd, 50);
if(retval == -1)
{
perror("设置最大连接数失败");
goto set_listen_err;
}
int client_fd;
struct sockaddr_in client_addr;
socklen_t sklen = sizeof(client_addr);
struct client_fd_sql client_fds = {.last=-1};
int i;
int max_fd = skt_fd;
fd_set readfds;
FD_ZERO(&readfds);
struct msg_data recv_msg;
while(1)
{
FD_SET(0, &readfds);
FD_SET(skt_fd, &readfds);
for(i=0; i<=client_fds.last; i++)
{
FD_SET(client_fds.client_fd[i], &readfds);
}
retval = select(max_fd+1, &readfds, NULL, NULL, NULL);
if(retval == -1)
{
perror("复用等待异常");
goto select_err;
}
else if(retval == 0)
{
printf("服用等待超时\n");
}
else if(retval)
{
for(i=0; i<=client_fds.last; i++)
{
if(FD_ISSET(client_fds.client_fd[i], &readfds))
{
bzero(&recv_msg, sizeof(recv_msg));
recv_size = recv(client_fds.client_fd[i], &recv_msg, sizeof(recv_msg), 0);
if(recv_size == -1)
{
perror("读取数据异常");
continue;
}else if(recv_size == 0)
{
printf("客户端断开链接\n");
memcpy(client_fds.client_fd+i, client_fds.client_fd+i+1, client_fds.last-i);
client_fds.last--;
break;
}
client_info_node *pos;
list_for_each(list_head, pos)
{
if(pos->client_fd == client_fds.client_fd[i])
continue;
printf("转发数据给端口号为%hu\n", pos->port);
send_size = send( pos->client_fd, &recv_msg, sizeof(recv_msg), 0);
if(send_size == -1)
break;
}
printf("接收到来自与客户端%ld个字节的数据:%s\n", recv_size, recv_msg.buffer);
}
}
if(FD_ISSET(0, &readfds))
{
bzero(&recv_msg, sizeof(recv_msg));
scanf("%s", recv_msg.buffer);
printf("从键盘当中获取到:%s\n", recv_msg.buffer);
}
if(FD_ISSET(skt_fd, &readfds))
{
cache_client_info.client_fd = accept(skt_fd, (struct sockaddr *)&client_addr, &sklen);
if(cache_client_info.client_fd == -1)
{
perror("客户端链接失败");
goto client_connect_err;
}
strcpy(cache_client_info.ip, inet_ntoa(client_addr.sin_addr));
cache_client_info.port = ntohs(client_addr.sin_port);
new_node = request_client_info_node(&cache_client_info);
insert_client_info_node_to_link_list(list_head, new_node);
printf("服务器:客户端连接成功\n");
printf("客户端信息:\n客户端IP为%s,端口号为%hu\n", cache_client_info.ip, cache_client_info.port);
client_fds.last++;
client_fds.client_fd[client_fds.last] = client_fd;
max_fd = max_fd>client_fd ? max_fd : client_fd;
pthread_create(&(new_node->tid), NULL, client_thread, list_head);
}
}
}
close(client_fd);
close(skt_fd);
return 0;
socket_recv_err:
select_err:
close(client_fd);
client_connect_err:
set_listen_err:
bind_socket_err:
close(skt_fd);
return -1;
}