#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct msg_t
{
char fb[5];
char msg[1024];
} msg_t;
typedef struct list
{
struct sockaddr_in addr;
struct list *next;
int fb;
} Node;
static int num;
static Node *list;
// 初始化好友列表
void init_list();
void init_list()
{
list = malloc(sizeof(Node));
memset(&list->addr, 0, sizeof(list->addr));
list->next = NULL;
list->fb = 0;
num = 0;
}
// 创建新节点
Node *create_Node();
Node *create_Node()
{
Node *New_Node = malloc(sizeof(Node));
memset(New_Node, 0, sizeof(Node));
New_Node->next = NULL;
return New_Node;
}
// 插入节点链表
Node *insert_list(Node *add_Node);
Node *insert_list(Node *add_Node)
{
add_Node->next = list->next;
list->next = add_Node;
}
// 删除节点
int rm_Node(Node *rm_Node);
int rm_Node(Node *rm_Node)
{
Node *temp = list;
while (1)
{
if (temp == NULL && temp != list)
{
return -1;
}
if (temp->next == rm_Node)
{
temp->next = rm_Node->next;
free(rm_Node);
return 0;
}
temp = temp->next;
}
return 0;
}
// 向所有客户机发送共同信息
void sendallfb(char *info);
void sendallfb(char *info)
{
Node *temp = list->next;
while (1)
{
if (temp == NULL)
{
break;
}
write(temp->fb, info, strlen(info));
temp = temp->next;
}
}
// 遍历好友列表
void print_list();
void print_list()
{
char info[521 * 10];
memset(info, 0, sizeof(memset));
char Tips[100] = {"---------------------好友列表-------------------\n"};
strcat(info, Tips);
if (list == NULL)
{
return;
}
if (list->next == NULL)
{
char no_num[50] = {"没有人上线\n"};
strcat(info, no_num);
}
char num_tips[100];
sprintf(num_tips, "有%d个好友在线\n", num);
strcat(info, num_tips);
char ip_fb[1000];
memset(ip_fb, 0, sizeof(ip_fb));
char temp_ip_fb[100];
Node *temp = list->next;
int onlinfb;
while (1)
{
if (temp == NULL)
{
break;
}
memset(temp_ip_fb, 0, sizeof(temp_ip_fb));
printf("IP:%s fb=%d(在线)\n", inet_ntoa(temp->addr.sin_addr), temp->fb);
sprintf(temp_ip_fb, "IP:%s fb=%d(在线)\n", inet_ntoa(temp->addr.sin_addr), temp->fb);
strcat(ip_fb, temp_ip_fb);
onlinfb = temp->fb;
temp = temp->next;
}
// sprintf(info, "%s%s%s", Tips, num_tips, ip_fb);
strcat(info, ip_fb);
printf("\n");
printf("info=%s\n", info);
sendallfb(info);
printf("\n");
}
int main(int argc, char const *argv[])
{
// 初始化好友列表
init_list();
// 创建socket
int fb = socket(AF_INET, SOCK_STREAM, 0);
if (fb < 0)
{
perror("socket");
return 0;
}
// 绑定主机信息
struct sockaddr_in addr; // 定义结构体
addr.sin_family = AF_INET; // 设置为IPV4
addr.sin_port = htons(8969); // 设置端口号为8080
addr.sin_addr.s_addr = INADDR_ANY;
int on = 1;
setsockopt(fb, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));//端口复用
// 绑定socket
if (bind(fb, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind fail");
}
// 设置监听,,模式
if (listen(fb, 100))
{
perror("listen");
}
int maxfb = fb;
while (1)
{
Node *temp = list->next;
// 多路复用
fd_set rfbs;
// 清空集合
FD_ZERO(&rfbs);
// 添加服务器描述符
FD_SET(fb, &rfbs);
// 添加标志输入描述符
FD_SET(0, &rfbs);
msg_t msg;
char op_tip[200];
memset(op_tip, 0, sizeof(op_tip));
strcat(op_tip, "--------------------操作提示--------------------\n");
while (1)
{
if (temp == NULL)
{
break;
}
FD_SET(temp->fb, &rfbs);
temp = temp->next;
}
if (num != 0)
{
strcat(op_tip, "发送信息格式:xxxx msg\n\n");
strcat(op_tip, "xxxx为对方fb,msg为短信内容\n\n");
}
sendallfb(op_tip);
int ret = select(maxfb + 1, &rfbs, NULL, NULL, NULL);
if (ret > 0)
{
temp = list->next;
while (1)
{
if (temp == NULL)
{
break;
}
if (FD_ISSET(temp->fb, &rfbs))
{
memset(&msg, 0, sizeof(msg));
if (read(temp->fb, &msg, sizeof(msg)) <= 0)
{
char down_line[200];
memset(down_line, 0, sizeof(down_line));
strcat(down_line, "--------------------下线通知--------------------\n");
char down_line_info[100];
sprintf(down_line_info, "您的好友IP=%s fb=%d下线\n", inet_ntoa(temp->addr.sin_addr), temp->fb);
strcat(down_line, down_line_info);
if (rm_Node(temp) == -1)
{
printf("删除节点失败\n");
}
sendallfb(down_line);
num--;
print_list();
break;
}
char msg_info[1000];
memset(msg_info, 0, sizeof(msg_info));
strcat(msg_info, "---------------------信息通知-------------------\n");
char rcv_info[100];
sprintf(rcv_info, "IP:%s fb=%d(在线)发来消息:\n", inet_ntoa(temp->addr.sin_addr), temp->fb);
strcat(msg_info, rcv_info);
msg.msg[strlen(msg.msg)] = '\n';
strcat(msg_info, msg.msg);
msg.fb[4] = '\0';
if (write(atoi(msg.fb), msg_info, strlen(msg_info)) < 0)
{
char error_info[70] = {"发送失败,短息格式有问题,或者对方不在线\n"};
write(temp->fb, error_info, strlen(error_info));
}
break;
}
temp = temp->next;
}
// 退出机制
if (msg.msg[0] == '1')
{
break;
}
// 监听键盘输入
if (FD_ISSET(0, &rfbs))
{
int op;
scanf("%d", &op);
if (op == 1)
{
break;
}
}
// 监听是否有人上线
if (FD_ISSET(fb, &rfbs))
{
char on_line_info[200];
memset(on_line_info, 0, sizeof(on_line_info));
socklen_t len = sizeof(list->addr);
Node *New_node = create_Node();
New_node->fb = accept(fb, (struct sockaddr *)&New_node->addr, &len);
if (New_node->fb > 0)
{
strcat(on_line_info, "---------------------上线通知-------------------\n");
char up_line[100];
memset(up_line, 0, sizeof(up_line));
sprintf(up_line, "您的好友IP=%s fb=%d已上线\n", inet_ntoa(New_node->addr.sin_addr), New_node->fb);
char myinfo[150];
sprintf(myinfo, "本机信息:IP=%s fb=%d\n", inet_ntoa(New_node->addr.sin_addr), New_node->fb);
write(New_node->fb, myinfo, strlen(myinfo));
strcat(on_line_info, up_line);
insert_list(New_node);
maxfb = New_node->fb;
num++;
sendallfb(on_line_info);
print_list();
}
}
}
}
// 退出关闭
Node *tempe = list->next;
close(fb);
while (1)
{
if (tempe == NULL)
{
break;
}
close(tempe->fb);
tempe = tempe->next;
}
return 0;
}
不懂可自行网主页寻找相应API解读,或私信(但不一定回)