创建服务端
功能:
1、实现10个用户的同时聊天,并且每两个用户之间都能聊天相互发送信息,并且具有群发消息的功能;
2、话语过滤功能:例如过滤信息中的fuck;
3、..............(另行添加)
实现:
1、在正常的TCP服务器的代码上进行改进,增加线程,以便实现多个用户的在线聊天;
2、函数模块:一个struct 用于收集中转用户的信息:套接字的文件描述符cfd & 用户的IP及端口信息sockaddr
一个结构体用于分发、存储用户的信息:用户的名字name & 套接字的文件描述符cfd
线程函数:实现消息的接受,发送,打印用户信息
话语过滤函数
#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;
}
客户端的实现
/* client .c*/
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#define PORT 9527
#define MAXDATASIZE 128
void* recv_proc(void* arg);
void* send_proc(void* arg);
int get_line(char *msg);
int main(int argc, char *argv[])
{
int fd;
pthread_t th1,th2;
struct hostent *he;
struct sockaddr_in server; //server's address info
char *defaultIP = "127.0.0.1";
//???
if(argc != 2) {
if((he = gethostbyname(defaultIP)) == NULL){
perror("gethostbyname() error");
exit(1);
}
}else{
if((he = gethostbyname(argv[1])) == NULL){
perror("gethostbyname() error");
exit(1);
}
}
if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("socket() error");
exit(1);
}
bzero(&server , sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr = *((struct in_addr *)he->h_addr);
if(connect(fd, (struct sockaddr *)&server,sizeof(struct sockaddr)) == -1){
perror("connect() error");
exit(1);
}
if(pthread_create(&th1, NULL, recv_proc, (void*)&fd)){
perror("recv pthread_creat() error");
close(fd);
exit(1);
}
if(pthread_create(&th2, NULL, send_proc, (void*)&fd)){
perror("send pthread_creat() error");
close(fd);
exit(1);
}
pthread_join(th1,NULL);
pthread_join(th2,NULL);
return 0;
}
void* recv_proc(void* arg)
{
char recvline[MAXDATASIZE];
int numbytes;
int sockfd;
printf("recv from server. \n");
sockfd = *((int*)arg);
while(1){
if((numbytes = recv(sockfd, recvline, MAXDATASIZE, 0)) > 0){
recvline[numbytes] = '\0';
printf("\n[recvice:] %s\n", recvline);
//clean output buffer
memset(recvline, '0', strlen(recvline)-1);
}else{
//printf("recv error/null. ");
}
}
}
void* send_proc(void* arg)
{
char sendline[MAXDATASIZE];
int numbytes;
int len;
int sockfd;
printf("send to server. \n");
sockfd = *((int*)arg);
while(1)
{
//send message to server
//when the string is not NULL , send another!
while((len =get_line(sendline)) != 0){
sendline[len] = '\0';
send(sockfd, sendline, strlen(sendline), 0);
}
}
}
int get_line(char *msg)
{
int i=0;
char temp;
printf("Input message:");
fflush(stdout);
while (1){
temp = getchar();
if (temp == '\r' || temp == '\n') {return i ;}
msg[i]=temp;
if(msg[i]==13){
msg[i]=0;
break;
}
fflush(stdout);
i++;
}
}
实现效果如下: