//TCP聊天室客户端
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
char* IP = "127.0.0.1";
//获取本机IP(回送地址--主要用于网络软件测试或本机进程间通信)
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_addr.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){
while(1){
char buf[200] = {};
if(recv(sockfd,buf,sizeof(buf),0)<=0){
return ;//结束线程
}
printf("%s\n",buf);
}
}
void sig_close(){
//关闭客户端的socket
close(sockfd);
exit(0);
}
int main(){
signal(SIGINT,sig_close);
printf("请输入昵称:");
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 <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
char* IP = "127.0.0.1";
//获取本机IP(回送地址--主要用于网络软件测试或本机进程间通信)
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;
//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\n",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=%dquit\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=%dquit\n",fd);
char msg[100] = {};
sprintf(msg,"欢送 %s 离开聊天室,再见!",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(){
//关闭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;
}