需求:软件划分为用户客户端和主播服务端两个软件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 ;
}
结果: