C语言实现网络聊天室 socket的简单应用
前言:环境是Linux ,使用了 socket和pthread,主要分为服务器端和客户端两部分,服务器端监听端口发来的请求,收到后向客户端发送一个消息,客户机负责发送消息并打印收到的消息.
编程模型
服务端s 客户端c
创建套接字(socket) 创建套接字(socket)
准备地址(自己的) 准备地址(服务器的,为连接准备)
绑定地址与socket
设置监听socket
等待连接 连接服务器
接受消息 发送消息
发送消息 接收消息
关闭套接字 关闭
客户端
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include <pthread.h>
#include <signal.h>
int sockfd;
void sigint(int signum)
{
close(sockfd);
puts("退出聊天!");
exit(0);
}
void* start(void* p)
{
int fd =*(int*)p;
while(1)
{
char buf[1024] = {};
if (0 >= recv(fd,buf,sizeof(buf),0) )
{
return NULL;
}
printf("\r%s\n",buf);
}
}
int main()
{
system("clear");
signal(SIGINT,sigint);
signal(SIGQUIT,sigint);
//创建socket对象
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(0>sockfd)
{
perror("socket");
return -1;
}
//准备通信地址
struct sockaddr_in addr ={};
addr.sin_family = AF_INET;
addr.sin_port = htons(1703);//端口号
addr.sin_addr.s_addr = inet_addr("192.168.1.118");//本地ip
//连接
if(0>connect(sockfd,(struct sockaddr*)&addr,sizeof(addr)))
{
perror("connect");
return -1;
}
pthread_t pid;
pthread_create(&pid,0,start,&sockfd);
//发送数据
while(1)
{
char buf[1024] ={};
char srt[255]={};
//printf(">>>");
gets(srt);
sprintf(buf,"\33[;44m%s\33[0m",srt);
send(sockfd,buf,strlen(buf)+1,0);
}
}
服务器端
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
typedef struct sockaddr SockAddr;
int fds[20];
char ip[20][20];
int size = 20;
void sigint(int signum)
{
for(int i=0;i<size;i++)
{
close(fds[i]);
}
puts("客户端已关闭!");
exit(0);
}
void* start(void* p)
{
//向所有聊天室成员 提示新用户来了
int fd =*(int*)p;
char buf3[1024] = {};
int index = 0;
for(int i=0;i<size;i++)
{
if(fds[i] == fd)
{
index = i;
break;
}
}
sprintf(buf3,"\33[;45m%s %s\33[0m ","欢迎",ip[index]);
for (int i=0;i<size;i++)
{
if (fds[i]!=0 && fds[i]!=fd)
{
printf("send to %d\n",fds[i]);
send(fds[i],buf3,strlen(buf3)+1,0);
}
}
// 收发数据
while(1)
{
char buf1[1024] = {};
char buf2[1024] = {};
//接受信息小于零,则用户退出
if (0 >= recv(fd,buf1,sizeof(buf1),0))
{
//退出后将位置空出来
for (int i=0;i<size;i++)
{
if (fd == fds[i])
{
fds[i] = 0;
break;
}
}
//提示用户退出
sprintf(buf2,"%s \33[;31m%s\33[0m ",ip[index],"已经退出!");
puts(buf2);
int i;
for ( i=0;i<size;i++)
{
if (fds[i]!=0 && fds[i]!=fd)
send(fds[i],buf2,strlen(buf2)+1,0);
}
send(fds[i],buf2,strlen(buf2)+1,0);
//结束线程
pthread_exit((void*)i);
}
//向所有用户发送信息
printf("%s:%s\n",ip[index],buf1);
sprintf(buf2,"\33[;42m%s\33[0m %s:%s","recv",ip[index],buf1);
for (int i=0;i<size;i++)
{
if (fds[i]!=0 && fds[i]!=fd)
{
printf("send to %d\n",fds[i]);
send(fds[i],buf2,strlen(buf2)+1,0);
}
}
}
}
int main()
{
signal(SIGINT,sigint);
signal(SIGQUIT,sigint);
// 创建socket对象
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(0 > sockfd)
{
perror("socket");
return -1;
}
// 准备通信地址
struct sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons(1710);
addr.sin_addr.s_addr = inet_addr("192.168.1.117");
// 绑定socket对象与通信地址
socklen_t len = sizeof(addr);
if(0 > bind(sockfd,(SockAddr*)&addr,len))
{
perror("bind");
return -1;
}
// 设置监听socket对象
listen(sockfd,size);
// 等待连接
while(1)
{
struct sockaddr_in from_addr;
int fd = accept(sockfd,(SockAddr*)&from_addr,&len);
if(0 > fd)
{
printf("客户端连接出错...\n");
continue;
}
int i;
for (i=0;i<size;i++)
{
if (fds[i] == 0)
{
//记录客户端的socket
fds[i] = fd;
//有客户端连接之后,启动线程给此客户服务
pthread_t pid;
pthread_create(&pid,NULL,start,&fd);
strcpy(ip[i],inet_ntoa(from_addr.sin_addr));
printf("客户端:%s连接成功!\n",ip[i]);
break;
}
}
if (size == i)
{
//发送给客户端说聊天室满了
char* str = "对不起,聊天室已经满了!";
send(fd,str,strlen(str),0);
close(fd);
}
}
}