在Linux下基于TCP网络通信的多人在线聊天室
一、使用原理:TCP网络传输;多线程事件处理;二、功能简介:(服务端)1、打开服务端,服务端进行初始化,并等待客户端的连接;2、打开客户端,输入服务端的IP地址与端口号;服务端会产生一个线程与新增的客户端进行通信,并分配客户端的名称,每连接一个客户端,服务端会产生一个线程与客户端进行通信;3、每新建一个客户端服务端会为客户端分配一个名字,依次为: ‘a’,'b','c',...
·
一、使用原理:
TCP网络传输;多线程事件处理;
二、功能简介:(服务端)
1、打开服务端,服务端进行初始化,并等待客户端的连接;
2、打开客户端,输入服务端的IP地址与端口号;服务端会产生一个线程与新增的客户端进行通信,并分配客户端的名称,每连接一个客户端,服务端会产生一个线程与客户端进行通信;
3、每新建一个客户端服务端会为客户端分配一个名字,依次为: ‘a’,'b','c',.....
三、使用方法
1、单独发送信息:每个客户端发送的信息会保存在服务端的缓冲区中,例如
客户端a发送:
a hello;
即发送给自己消息:
hello;
客户端a发送:
b hello;
即发送给客户端b消息:
hello;
2、群发消息:
在发送的消息前面加上 ‘x’ ,即触发群发消息的功能;
四、编译
由于使用了线程的功能,所以在编译的时候 gcc server.c -lpthead -o server 加上线程库;
五、代码(server.c) 客户端可以先使用 nc 127.0.0.1 9527 (服务端IP加端口号) 进行调试
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
//#include<ctype.h>
#include<unistd.h>
//#include<errno.h>
#include<pthread.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define SERV_PORT 9527 /*服务端的端口号 */
#define ONLINEMAX 10 /*同时在线的最大人数 */
void *ChatOnline(void *arg); /*线程的聊天,消息处理函数 */
void fuck_filter(const char* buf);
int UserSelect(char name);
/*用于用户信息的临时参数存储 -> 套接字的文件描述符 && IP+PORT */
struct arg_user
{
int cfd;
struct sockaddr_in clit_addr;
};
/*用户信息的存放函数 ->用户名 && 套接字文件描述符 */
struct user
{
char name;
int user_cfd;
}clit_user[ONLINEMAX];
/*报错函数 */
void sys_err(const char *str)
{
perror(str);
exit(1);
}
static int user_number = 0; /* 用户的号数*/
int main()
{
int sfd = 0,cfd = 0;
int ret = 0,i = 0,tmp = 0;
char buf[BUFSIZ]; //BUFSIZ大小为8192字节
struct sockaddr_in serv_addr,clit_addr;
struct arg_user *arg;
socklen_t clit_addr_len;
pthread_t pthread;
/*设置 struct sockaddr_in 里面的内容 采用IPv4 端口号为9527 IP号由INADDR_ANY生成的二进制的IP地址 */
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*生成套接字,并校验*/
sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd == -1){
sys_err("socket error");
}
printf("socket .....");
/*绑定端口号+IP地址 */
bind(sfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
printf("bind .......");
/*设置监听的上限 */
listen(sfd,20);
printf("listen .....");
int opt = SO_REUSEADDR;
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
/*setsockopt()用来设置参数s所指定的socket状态。
参数level代表欲设置的网络层,一般设成SOL_SOCKET以存取socket层。
参数optname代表欲设置的选项,有下列几种数值:SO_REUSEADDR 允许在bind()过程中本地地址可重复使用
参数 optval代表欲设置的值,参数optlen则为optval的长度。
返回值 成功则返回0,若有错误则返回-1,错误原因存于errno。*/
/*监听,阻塞至有客户端连接,并返回一个新的套接字与客户端建立通讯 */
clit_addr_len = sizeof(clit_addr);
/*读取客户端发来的信息,并转化为大写 */
while(1){
printf("accept .....\n");
cfd = accept(sfd,(struct sockaddr *)&clit_addr,&clit_addr_len);
if(cfd == -1) sys_err("accpet error");
// printf("client's IP = %s",inet_ntoa(clit_addr.sin_addr));
/*指向结构体的结构体要先分配空间 将用户信息收集起来 */
arg = malloc(sizeof(struct arg_user));
arg->cfd = cfd;
memcpy((void *)&arg->clit_addr, &clit_addr, sizeof(clit_addr));
tmp = pthread_create(&pthread,NULL,ChatOnline,(void*)arg);
if(tmp != 0) sys_err("pthread_create faile");
}
close(sfd);
close(cfd);
return 0;
}
void *ChatOnline(void *arg)
{
int cfd = 0;int ret = 0;
struct sockaddr_in clit_addr;
struct arg_user *n_arg;
char buf[BUFSIZ];
// char *p=NULL;
char name;
struct pid{
int pid_pid;
char pid_name;
}my_pid;
n_arg = malloc(sizeof(struct arg_user));
n_arg = arg;
cfd = n_arg->cfd;
clit_addr = n_arg->clit_addr;
clit_user[user_number].name = 'a'+user_number;
clit_user[user_number].user_cfd = cfd;
my_pid.pid_name = clit_user[user_number].name;
if(user_number++ > ONLINEMAX) user_number = 0;
printf("client's IP = %s...name = %c\n",inet_ntoa(clit_addr.sin_addr),my_pid.pid_name);
my_pid.pid_pid = pthread_self();
while(1){
memset(buf,0,BUFSIZ);
ret = read(cfd,buf,sizeof(buf));
if(ret == 0 || ret == -1){
perror("client disconnec");
close(cfd);
break;
}
write(STDOUT_FILENO,buf,ret);
fuck_filter(buf); //话语过滤
name = buf[0];
if(name == 'x'){
int i;
for(i = 0;i < ONLINEMAX;i++){
if(clit_user[i].user_cfd > 0){
// write(clit_user[i].user_cfd,"[THE MESSAGE From]:->",28);
// write(clit_user[i].user_cfd,p,sizeof(p));
write(clit_user[i].user_cfd,buf,ret);
}
}
}
int user_cfd = UserSelect(name);
if(user_cfd > 0 ){
write(user_cfd,buf,ret);
}
}
}
int UserSelect(char name)
{
int ufd = 0;
int i;
for(i=0;i<= ONLINEMAX;i++)
{
if(name == clit_user[i].name)
return clit_user[i].user_cfd;
}
return ufd;
}
void fuck_filter(const char* buf)
{
char buf_fuck[] = "fuck";
char * p = NULL;
do{
p = strstr(buf,buf_fuck);
if(p != 0){
*p = '*';
*(++p) = '*';
*(++p) = '*';
*(++p) = '*';
}
}while(p != 0);
}
更多推荐
已为社区贡献1条内容
所有评论(0)