/*
TCP聊天室 客户端
*/
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#include<netinet/in.h>
//一些准备工作
char* IP = "172.30.11.104";//127.0.0.1 本机地址,回送地址,用于网络软件测试 或本机通信
short PORT = 10222; // 端口
typedef struct sockaddr SA; //用做类型转换
int sockfd= 0;
char name[20] = {};
//1 启动客户端,连接服务器
void init()
{
printf("聊天室客户端开始启动。。\n");
sockfd = socket(PF_INET,SOCK_STREAM,0);
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(PORT);
addr.sin_family.s_addr = inet_addr(IP);
//连接
if(connect(sockfd,(SA*)&addr,sizeof(addr)) ==-1)
{
perror("无法连接服务器");
printf("客户端启动失败\n");
exit(-1);
}
printf("客户端启动成功\n");
}
//2 开始通信
void start()
{
//主要是用来发送消息
//发消息之前,启动一个线程 用来接收消息
pthread_t pid;
void* recv_thread(void* );
pthread_create(&pid,0,recv_thread,0);
while(1)
{
char buf[100] = {};
scanf("%s",buf);//读取客户的输入
char msg[200] = {};
sprintf(msg,"%s 说:%s",name,buf);
send(sockfd,msg,strlen(msg),0);
}
}
//线程函数 ,用来接收消息
void* recv_thread(void* p)
{
char buf[200] = {};
if(recv(sockfd,buf,sizeof(buf),0)<=0)
{
return ; //结束线程
}
printf("%s\n",buf);
}
void sig_close(int signo)
{//关闭客户端socket
close(sockfd);
exit(0);
}
int main()
{
signal(SIGINT,sig_close);
printf("请输入昵称:\n");
scanf("%s",name);
init(); //启动客户端 连接到服务器
send(sockfd,name,strlen(name),0);
start();
}
/*
TCP聊天室服务器
*/
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#include<netinet/in.h>
//一些准备工作
char* IP = "172.30.11.104";//127.0.0.1 本机地址,回送地址,用于网络软件测试 或本机通信
short PORT = 10222; // 端口
typedef struct sockaddr SA; //用做类型转换
struct client
{
char name[20];//记录客户端的昵称
int fds; //客户端的socket描述符
};
struct client c[100] = {0};//记录客户端的结构体数组 最多记录了100个
int size = 0; //记录客户端的个数,也可以用来遍历客户端结构体
int sockfd = 0; //服务器的sockt
//1 初始化服务器的网络,创建socket
void init()
{
printf("聊天室服务器开始启动……\n");
sockfd = socket(PF_INET,SOCK_STREAM,0);
if(sockfd == -1) perror("socket创建失败,服务器启动失败"),exit(-1);
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(IP);
if(bind(sockfd,(SA*)&addr,sizeof(addr))==-1)
{
perror("绑定失败");
printf("服务器启动失败\n");
exit(-1);
}
printf("绑定成功\n");
if(listen(sockfd,100) == -1)
{
perror("设置监听失败");
printf("服务器启动失败\n");
exit(-1);
}
printf("设置监听成功\n");
//等待客户端连接到另一个函数中
printf("初始化服务器成功\n");
}
/*
辅助函数,用来分发消息
*/
void sendMsgToAll(char* msg)
{
int i = 0;
for( i = 0;i<size;i++)
{
printf("sendto %d\n",c[i].fds);
send(c[i].fds,msg,strlen(msg),0);
}
}
//线程函数,用来接收客户端发来的消息,并且把消息发送给所有客户端
void* service_thread(void* p)
{
int fd = *(int*)p; //拿到客户端的socket描述符
printf("pthread = %d",fd); //线程对应客户端
//保留客户端的信息
c[size].fds = fd;
char name[20] = {};
if(recv(fd,name,sizeof(name),0)>0) //接收昵称
{
strcpy(c[size].name,name);
}
size++;
//先群发一条消息,表示欢迎 也可以通知其他客户端有人连接了 进入聊天室
char tishi[100];
sprintf(tishi,"热烈欢迎%s登陆聊天室。。",name);
//群发消息
sendMsgToAll(tishi);
//通信部分,收发消息
while(1)
{
char buf[200] = {};
if(recv(fd,buf,sizeof(buf),0) == 0)
{
printf("fd = %d quit\n",fd);
//有客户端断开
int i;
char name[20] = {};
for(i= 0;i<size;i++)
{
if(c[i].fds == fd)
{
strcpy(name,c[i].name);
c[i].fds = c[size-1].fds;
strcpy(c[i].name,c[size-1].name);
}
}
size--;
printf("quit->fd=%d\n",fd);
char msg[100] = {};
sprintf(msg,"欢送 %s 离开聊天室,再见\n",name);
sendMsgToAll(msg);
close(fd);
return ; //客户端退出 结束线程
}
sendMsgToAll(buf); //成功接收到消息,就直接所有的客户端
}
}
//等待客户端连接,启动服务器服务
void service()
{
printf("服务器开始服务\n");
while(1)
{
struct sockaddr_in fromaddr; //存储客户端的通信地址
socklen_t len = sizeof(fromaddr);
int fd = accept(sockfd,(SA*)&fromaddr,&len);
if(fd == -1)
{
printf("客户端连接出错\n");
continue;
}
//如果客户成功连接
//开启线程,为该客户端进行服务
printf("fd =%d\n",fd);
pthread_t pid;
pthread_create(&pid,0,service_thread,&fd);
}
}
void sig_close(int signo)
{ //关闭socket
int i = 0;
for(;i<size;i++)
{
if(c[i].fds!=0)
close(c[i].fds);
}
close(sockfd);//服务器的socket;
printf("服务器已经关闭\n");
exit(0);
}
int main()
{
signal(SIGINT,sig_close);//做好善后工作
init();
service();
return 0;
}