需求:
软件划分为用户客户端和主播服务端两个软件client.c和server.c
用户客户端负责:
1.接收用户的昵称
2.接收用户输入的信息,能够将信息发送给服务端
3.接收服务端回复的数据信息,并完成显示
主播服务端负责:
1.对所有加入直播间的用户的IP地址和端口实现管理(加入、退出)
2.当有新的客户端加入时,能够向所有客户端提示:"欢迎 XXX 用户进入直播间"
3.当有客户端退出时,能够向所有客户端提示:"XXX 离开直播间"
4.能够实现客户端聊天内容的转发,当某个客户端发送聊天信息时,能够将该信息转给除了该用户之外聊天室内所有其余客户端用户
head.h文件
# ifndef __HEAD_H__
# define __HEAD_H__
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <unistd.h>
# include <fcntl.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <dirent.h>
# include <time.h>
# include <pwd.h>
# include <grp.h>
# include <pthread.h>
# include <semaphore.h>
# include <signal.h>
# include <sys/ipc.h>
# include <sys/msg.h>
# include <sys/shm.h>
# include <sys/sem.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <netinet/ip.h>
# include <netinet/in.h>
struct address
{
int mark;
struct sockaddr_in addr;
} ;
struct msgbuf {
int type;
char name[ 32 ] ;
char text[ 512 ] ;
} ;
# define MSG_TYPE_START 100
# define MSG_TYPE_END 200
# define MSG_TYPE_CHAT 300
# define RECV_ADDR "192.168.1.152"
# define RECV_PORT 50000
# endif
client.c
# include "head.h"
char name[ 32 ] = { 0 } ;
int sockfd = 0 ;
struct sockaddr_in recvaddr;
pthread_t tid_send;
pthread_t tid_recv;
void * sendfun ( void * arg)
{
struct msgbuf sendmsg;
ssize_t nsize = 0 ;
while ( 1 )
{
memset ( & sendmsg, 0 , sizeof ( sendmsg) ) ;
sendmsg. type = MSG_TYPE_CHAT;
sprintf ( sendmsg. name, "%s" , name) ;
gets ( sendmsg. text) ;
if ( ! strcmp ( sendmsg. text, ".quit" ) )
{
sendmsg. type = MSG_TYPE_END;
}
nsize = sendto ( sockfd, & sendmsg, sizeof ( sendmsg) , 0 , ( struct sockaddr * ) & recvaddr, sizeof ( recvaddr) ) ;
if ( - 1 == nsize)
{
perror ( "fail to sendto" ) ;
return NULL ;
}
if ( sendmsg. type == MSG_TYPE_END)
{
break ;
}
}
pthread_cancel ( tid_recv) ;
return NULL ;
}
void * recvfun ( void * arg)
{
struct msgbuf recvmsg;
ssize_t nsize = 0 ;
while ( 1 )
{
memset ( & recvmsg, 0 , sizeof ( recvmsg) ) ;
nsize = recvfrom ( sockfd, & recvmsg, sizeof ( recvmsg) , 0 , NULL , NULL ) ;
if ( - 1 == nsize)
{
perror ( "fail to recvfrom" ) ;
return NULL ;
}
if ( recvmsg. type == MSG_TYPE_CHAT)
{
printf ( "%s(%s:%d)>%s\n" , recvmsg. name, RECV_ADDR, RECV_PORT, recvmsg. text) ;
}
else if ( recvmsg. type == MSG_TYPE_END)
{
break ;
}
}
pthread_cancel ( tid_send) ;
return NULL ;
}
int main ( void )
{
struct msgbuf sendmsg;
ssize_t nsize = 0 ;
recvaddr. sin_family = AF_INET;
recvaddr. sin_port = htons ( RECV_PORT) ;
recvaddr. sin_addr. s_addr = inet_addr ( RECV_ADDR) ;
printf ( "请输入您的昵称:\n" ) ;
gets ( name) ;
sockfd = socket ( AF_INET, SOCK_DGRAM, 0 ) ;
if ( - 1 == sockfd)
{
perror ( "fail to socket" ) ;
return - 1 ;
}
memset ( & sendmsg, 0 , sizeof ( sendmsg) ) ;
sendmsg. type = MSG_TYPE_START;
sprintf ( sendmsg. name, "%s" , name) ;
nsize = sendto ( sockfd, & sendmsg, sizeof ( sendmsg) , 0 , ( struct sockaddr * ) & recvaddr, sizeof ( recvaddr) ) ;
if ( - 1 == nsize)
{
perror ( "fail to sendto" ) ;
return - 1 ;
}
pthread_create ( & tid_send, NULL , sendfun, NULL ) ;
pthread_create ( & tid_recv, NULL , recvfun, NULL ) ;
pthread_join ( tid_send, NULL ) ;
pthread_join ( tid_recv, NULL ) ;
close ( sockfd) ;
return 0 ;
}
server.c
# include "head.h"
struct address ClientIpList[ 100 ] ;
int AddClientIp ( struct sockaddr_in TmpAddr)
{
int i = 0 ;
for ( i = 0 ; i < 100 ; ++ i)
{
if ( ClientIpList[ i] . mark == 0 )
{
ClientIpList[ i] . addr = TmpAddr;
ClientIpList[ i] . mark = 1 ;
break ;
}
}
return 0 ;
}
int DelClientIp ( struct sockaddr_in TmpAddr)
{
int i = 0 ;
for ( i = 0 ; i < 100 ; ++ i)
{
if ( 0 == memcmp ( & TmpAddr, & ClientIpList[ i] . addr, sizeof ( TmpAddr) ) )
{
ClientIpList[ i] . mark = 0 ;
break ;
}
}
return 0 ;
}
int BoardcastClientIp ( int sockfd, struct sockaddr_in TmpAddr, struct msgbuf TmpMes)
{
int i = 0 ;
ssize_t nsize = 0 ;
for ( i = 0 ; i < 100 ; ++ i)
{
if ( ClientIpList[ i] . mark == 0 )
{
continue ;
}
if ( 0 != memcmp ( & TmpAddr, & ClientIpList[ i] . addr, sizeof ( TmpAddr) ) )
{
nsize = sendto ( sockfd, & TmpMes, sizeof ( TmpMes) , 0 , ( struct sockaddr * ) & ClientIpList[ i] . addr, sizeof ( ClientIpList[ i] . addr) ) ;
if ( - 1 == nsize)
{
continue ;
}
}
}
return 0 ;
}
int main ( void )
{
int sockfd = 0 ;
int ret = 0 ;
ssize_t nsize = 0 ;
struct msgbuf recvmes;
struct sockaddr_in recvaddr;
struct sockaddr_in sendaddr;
socklen_t addrlen = sizeof ( sendaddr) ;
recvaddr. sin_family = AF_INET;
recvaddr. sin_port = htons ( RECV_PORT) ;
recvaddr. sin_addr. s_addr = INADDR_ANY;
sockfd = socket ( AF_INET, SOCK_DGRAM, 0 ) ;
if ( - 1 == sockfd)
{
perror ( "fail to socket" ) ;
return - 1 ;
}
ret = bind ( sockfd, ( struct sockaddr * ) & recvaddr, sizeof ( recvaddr) ) ;
if ( - 1 == ret)
{
perror ( "fail to bind" ) ;
return - 1 ;
}
memset ( & ClientIpList, 0 , sizeof ( ClientIpList) ) ;
while ( 1 )
{
memset ( & recvmes, 0 , sizeof ( recvmes) ) ;
nsize = recvfrom ( sockfd, & recvmes, sizeof ( recvmes) , 0 , ( struct sockaddr * ) & sendaddr, & addrlen) ;
if ( - 1 == nsize)
{
perror ( "fail to recvfrom" ) ;
return - 1 ;
}
if ( recvmes. type == MSG_TYPE_START)
{
AddClientIp ( sendaddr) ;
recvmes. type = MSG_TYPE_CHAT;
sprintf ( recvmes. text, "%s" , recvmes. name) ;
}
else if ( recvmes. type == MSG_TYPE_END)
{
DelClientIp ( sendaddr) ;
recvmes. type = MSG_TYPE_CHAT;
sprintf ( recvmes. text, "%s" , recvmes. name) ;
}
if ( recvmes. type == MSG_TYPE_CHAT)
{
BoardcastClientIp ( sockfd, sendaddr, recvmes) ;
}
}
close ( sockfd) ;
return 0 ;
}
结果: