服务器端:
启动服务器后,等待客户端的连接。连接一个客户端,启动一个线程。客户端的动态,发送的消息,都会传给服务器。
客户端:
登录输入姓名,然后连接服务器,进入聊天室。用户可以发送自己的消息和接收从服务器传递过来的别人发送的消息,当输入bye的时候,会退出聊天室。
server.c
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #include<unistd.h>
5 #include<netinet/in.h>
6 #include<arpa/inet.h>
7 #include<sys/socket.h>
8 #include<pthread.h>
9
10 int sockfd;//服务器端的文件描述符,socket的返回值
11 int fds[100];//与客户端连接的描述符
12 int size = 100;//最大连接人数
13 #define PORT 10222//端口号
14
15 void init()
16 {
17 sockfd = socket(AF_INET,SOCK_STREAM,0);//socket
18 if(sockfd == -1)
19 {
20 perror("创建socket失败");
21 exit(-1);
22 }
23
24 //printf("创建socket成功\n");
25 struct sockaddr_in addr;//服务器的地址结构
26 addr.sin_family = AF_INET;//流式套接字
27 addr.sin_port = htons(PORT);//设置端口号
28 addr.sin_addr.s_addr = htonl(INADDR_ANY);//设置IP地址为本机的IP地址
29 if(bind(sockfd,(struct sockaddr*)&addr,sizeof(struct sockaddr)) == -1)//将socket的返回值sockfd与地址结构想绑定
30 {
31 perror("绑定失败");
32 exit(-1);
33 }
34 if(listen(sockfd,100) == -1)//设置监听队列。长度为100
35 {
36 perror("设置监听失败");
37 exit(-1);
38 }
39 }
40
41 void* service_thread(void* p)
42 {
43 int fd = *(int*)p;
44 printf("pthread = %d\n",fd);
45 while(1)
46 {
47 char buf[100] = {};
48 if(recv(fd,buf,sizeof(buf),0)<=0)//如果没有接收到数据,说明客户端那边已经下线
49 {
50 int i;
51 for(i=0;i<size;i++)
52 {
53 if(fd == fds[i])//将已经下线的客户端的fd描述符清零
54 {
55 fds[i] = 0;
56 break;
57 }
58 }
59 printf("退出:fd = %dquit\n",fd);
60 pthread_exit(&i);
61 }
62 int i;
63 for(i=0;i<size;i++)//将消息逐一发送给连接的客户端
64 {
65 if(fds[i]!=0)
66 {
67 printf("发送消息给%d\n",fds[i]);
68 send(fds[i],buf,strlen(buf),0);
69 }
70
71 }
72
73 }
74 }
75
76 void service()
77 {
78 printf("服务器启动\n");
79 while(1)
80 {
81 struct sockaddr_in fromaddr;//客户端的地址结构
82 socklen_t len = sizeof(fromaddr);//客户端的地址结构的大小
83 int fd = accept(sockfd,(struct sockaddr*)&fromaddr,&len);//fd为和客户端相连接的描述符
84 if(fd == -1)
85 {
86 printf("客户端连接出错...\n");
87 continue;
88 }
89 int i=0;
90 for(i=0;i<size;i++)//将新连接的fd放入fds的数组中
91 {
92 if(fds[i] == 0)
93 {
94 fds[i] = fd;
95 printf("fd = %d\n",fd);
96
97 pthread_t tid;//这是一个线程的tid
98 pthread_create(&tid,0,service_thread,&fd);//创建一个线程
99 break;
100 }
101
102 if(size == i)
103 {
104 char* str = "对不起,聊天室已经满了!";
105 send(fd,str,strlen(str),0);
106 close(fd);
107 }
108 }
109
110 }
111 }
112
113 int main()
114 {
115 init();
116 service();
117 return 0;
118 }
client.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5 #include<sys/socket.h>
6 #include<netinet/in.h>
7 #include<arpa/inet.h>
8 #include<pthread.h>
9
10 int sockfdi;//客户端的socket返回值
11 #define PORT 10222//端口号
12 char name[30];//存储姓名的数组
13
14 void init()
15 {
16 sockfd = socket(PF_INET,SOCK_STREAM,0);
17 struct sockaddr_in addr;//客户端地址结构
18 addr.sin_family = AF_INET;//流式套接字
19 addr.sin_port = htons(PORT);//地址端口
20 addr.sin_addr.s_addr = htonl(INADDR_ANY);//设置IP地址为本机IP地址
21 if(connect(sockfd,(struct sockaddr*)&addr,sizeof(addr)) == -1)//与服务器连接
22 {
23 perror("无法连接到服务器");
24 exit(1);
25 }
26 printf("客户端启动成功\n");
27 }
28
29 void start()
30 {
31 pthread_t id;//线程id
32 void * recv_thread(void*);//函数声明
33 pthread_create(&id,0,recv_thread,0);//创建线程
34 char buf2[100] = {};
35 sprintf(buf2,"%s进入了聊天室",name);//将姓名打印在屏幕上并且放入buf2中
36 send(sockfd,buf2,strlen(buf2),0);//将buf2中的数据发给客户端
37 while(1)
38 {
39 char buf[100] = {};
40 scanf("%s",buf);//这里输入我们要说的话
41 char msg[131] = {};//存储我们的名字加要说的话
42 sprintf(msg,"%s:%s",name,buf);//打印在自己的屏幕上并且放到msg中
43 send(sockfd,msg,strlen(msg),0);//发送给服务器
44 if(strcmp(buf,"buy") == 0)//如果自己输入了bye,表示退出聊天室
45 {
46 memset(buf2,0,sizeof(buf2));
47 sprintf(buf2,"%s退出了聊天室",name);
48 send(sockfd,buf2,strlen(buf2),0);
49 break;
50 }
51 }
52 close(sockfd);
53 }
54
55 void* recv_thread(void* p)
56 {
57 while(1)
58 {
59 char buf[100] = {};
60 if(recv(sockfd,buf,sizeof(buf),0)<=0)//接收从服务器发来的消息
61 {
62 return 0;
63 }
64 printf("%s\n",buf);//将从服务器接收的消息打印在屏幕上
65 }
66 }
67
68 int main()
69 {
70 init();
71 printf("请输入你的名字:");
72 scanf("%s",name);
73 start();
74 return 0;
75 }