【1】服务器代码
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "head.h"
// 服务器-------------------------------------------------------------------------》短信的接收方
/*创建一个空的单向链表*/
Node_p Create();
/*登录,聊天,退出*/
void login(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr);
void chat(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr);
void quit(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr);
int main(int argc, char const *argv[])
{
int fd_s;
// 1.创建数据报套接字(socket)------------------》有手机
fd_s = socket(AF_INET, SOCK_DGRAM, 0);
if (fd_s < 0)
{
perror("soc err\n");
return -1;
}
// printf("%d\n", fd_s);
// 2.指定网络信息--------------------------------------》有号码
struct sockaddr_in saddr, caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = INADDR_ANY;
int len = sizeof(caddr);
// 3.绑定套接字(bind)------------------------------》绑定手机
if (bind(fd_s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind err\n");
return -1;
}
// printf("bind ok\n");
printf("欢迎使用欢欢聊天室\n");
Msg msg;
Node_p p = Create(); // 创建空链表
pid_t pid;
pid = fork(); // 创建新进程
if (pid < 0)
{
perror("fork err\n");
return -1;
}
else if (pid == 0)
{
fgets(msg.text, sizeof(msg.text), stdin);
if (msg.text[strlen(msg.text) - 1] == '\n')
msg.text[strlen(msg.text) - 1] = '\0';
msg.type = 'C';
strcpy(msg.name, "server");
sendto(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, len);
}
else
{
// 4.接收、发送消息(recvfrom sendto)-------》收短信
while (1)
{
int ret;
ret = recvfrom(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&caddr, &len);
if (ret < 0)
{
perror("recv err\n");
return -1;
}
// printf("addr: %s port: %d\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
if (msg.type == 'L')
{
// printf("addr: %s port: %d\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
printf("<%s> 已登录\n", msg.name);
sprintf(msg.text, "<%s> 已登录", msg.name);
login(fd_s, msg, p, caddr);
}
else if (msg.type == 'C')
{
printf("[%s]: %s\n", msg.name, msg.text);
chat(fd_s, msg, p, caddr);
}
else if (msg.type == 'Q')
{
sprintf(msg.text, "<%s> 已下线", msg.name);
printf("<%s> 已下线\n", msg.name);
quit(fd_s, msg, p, caddr);
}
}
}
// 5.关闭套接字(close)----------------------------》接收完毕
close(fd_s);
return 0;
}
/*创空表*/
Node_p Create()
{
Node_p p = (Node_p)malloc(sizeof(Node_t)); // 开辟一个节点大小的堆区空间
if (NULL == p) // 开辟失败
{
printf("malloc lost");
return NULL;
}
p->next = NULL; // 初始化头节点指针域
return p; // 开辟成功,返回
}
/*登录*/
void login(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr)
{
while (p->next != NULL)
{
p = p->next;
sendto(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
}
/*创建新的节点*/
Node_p p_new = (Node_p)malloc(sizeof(Node_t));
if (p_new == NULL)
{
perror("malloc err\n");
return;
}
/*初始化节点*/
p_new->addr = caddr;
p_new->next = NULL;
/*将新节点连接到链表中*/
p->next = p_new;
// p = p_new;
return;
}
/*聊天*/
void chat(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr)
{
while (p->next != NULL)
{
p = p->next;
if ((memcmp(&(p->addr), &caddr, sizeof(caddr))) == 0)
{
continue;
}
sendto(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
}
}
/*退出*/
void quit(int fd_s, Msg msg, Node_p p, struct sockaddr_in caddr)
{
while (p->next != NULL)
{
if ((memcmp(&(p->next->addr), &caddr, sizeof(caddr))) == 0)
{
Node_p p_del = NULL;
p_del = p->next;
p->next = p_del->next;
free(p_del);
p_del = NULL;
continue;
}
else
{
p = p->next;
sendto(fd_s, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
}
}
return;
}
【2】客户端代码
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include "head.h"
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
// 客户端---------------------------------------------------------------------------》短信的发送方
struct sockaddr_in saddr;
int len = sizeof(saddr);
int main(int argc, char const *argv[])
{
// 1.创建数据报套接字(socket)------------------》有手机
int fd_c;
fd_c = socket(AF_INET, SOCK_DGRAM, 0);
if (fd_c < 0)
{
perror("soc err\n");
return -1;
}
// printf("%d\n", fd_c);
// 2.指定网络信息--------------------------------------》有对方号码
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = inet_addr("192.168.31.187");
Msg msg;
msg.type = 'L';
printf("欢迎使用欢欢聊天室\n");
printf("请输入用户名:");
fgets(msg.name, N, stdin);
if (msg.name[strlen(msg.name) - 1] == '\n')
msg.name[strlen(msg.name) - 1] = '\0';
sendto(fd_c, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, sizeof(saddr));
pid_t pid = fork();
if (pid < 0)
{
perror("fork err");
exit(-1);
}
else if (pid == 0)
{
while (1)
{
if (recvfrom(fd_c, &msg, sizeof(msg), 0, NULL, NULL) < 0)
{
perror("recvfrom err");
return -1;
}
if (msg.type == 'L')
printf("%s\n", msg.text);
else if (msg.type == 'C')
printf("[%s]:%s\n", msg.name, msg.text);
else if (msg.type == 'Q')
printf("%s\n", msg.text);
}
}
else
{
while (1)
{
fgets(msg.text, sizeof(msg.text), stdin);
if (msg.text[strlen(msg.text) - 1] == '\n')
msg.text[strlen(msg.text) - 1] = '\0';
if (strcmp(msg.text, "quit") == 0)
{
msg.type = 'Q';
sendto(fd_c, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, len);
kill(pid, SIGKILL);
wait(NULL);
exit(-1);
}
else
{
msg.type = 'C';
}
// 发送消息
sendto(fd_c, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, len);
}
}
close(fd_c);
return 0;
}