简单的聊天室
来源:互联网 发布:光纤销售数据 编辑:程序博客网 时间:2024/05/21 15:49
简介:简单的聊天室,实现注册,群发消息,私聊消息的功能;
这是一个简单的多个客户端和服务器端的通信;
大体的是客户端创建连接服务器端的套接字,连接到服务器;
连接上之后就是调用功能函数,功能函数中写个switch(),对功能进行选择;
这些功能的实现基本都是客户端消息写给服务器端,在从服务器端读消息(一个客户端怎么在发消息的同时又读消息呢,所以进行读写分离,在一个客户端注册完成之后就开辟一个线程);
**消息的发送不管是什么都一个结构体全部发送过去;
**客户端代码:**#include <sys/types.h>#include <sys/socket.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <arpa/inet.h>#define PORT 9999char myName[20];struct Msg{ char msg[1024]; // 消息内容 char toname[20]; char fromname[20]; int cmd; // 消息类型}; // 界面 void interface() { printf ("1、注册\n"); printf ("2、聊天\n"); printf ("3、私聊\n"); } void * readMsg(void *v) { int socketfd = (int)v; struct Msg msg; while (1) { read (socketfd, &msg, sizeof(msg)); switch (msg.cmd) { case 2: // 群聊 printf ("收到一条消息: %s\n", msg.msg); break; case 3: // 私聊 printf ("%s 给你发一条消息:%s\n", msg.fromname, msg.msg); break; } } } void reg(int socketfd) { struct Msg msg; msg.cmd = 1; printf ("请输入用户名:\n"); fgets(myName, 20, stdin); strcpy (msg.msg, myName); write (socketfd, &msg, sizeof(msg)); read (socketfd, &msg, sizeof(msg)); if (msg.cmd == 1001) { printf ("注册成功\n"); } else if (msg.cmd == -1) { printf ("注册失败\n"); } sleep(1); pthread_t id; pthread_create(&id, NULL, readMsg, (void *)socketfd); pthread_detach(id); // 线程分离 } void chat(int socketfd) { struct Msg msg; msg.cmd = 2; printf ("请输入要发送的内容: \n"); fgets(msg.msg, 1024, stdin); write (socketfd, &msg, sizeof(msg)); } void chat2(int socketfd) { struct Msg msg; msg.cmd = 3; printf ("请输入要发送的对象名称: \n"); fgets(msg.toname, 20, stdin); printf ("请输入要发送的内容: \n"); fgets(msg.msg, 1024, stdin); strcpy (msg.fromname, myName); write (socketfd, &msg, sizeof(msg)); }// 客户端向服务器发送数据void ask_server(int socketfd){ char ch[2]; while (1) { interface(); fgets(ch, 2, stdin); while(getchar()!= '\n'); switch(ch[0]) { case '1': // 注册 reg(socketfd); break; case '2': // 聊天 chat(socketfd); break; case '3': // 私聊 chat2(socketfd); break; } system("clear"); }}int main(){ // 创建与服务器通信的套接字 int socketfd = socket(AF_INET, SOCK_STREAM, 0); if (socketfd == -1) { perror ("socket"); return -1; } // 连接服务器 struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; // 设置地址族 addr.sin_port = htons(PORT); // 设置本地端口 inet_aton("127.0.0.1",&(addr.sin_addr)); // 连接服务器,如果成功,返回0,如果失败,返回-1 // 成功的情况下,可以通过socketfd与服务器进行通信 int ret = connect(socketfd, (struct sockaddr *)&addr, sizeof(addr)); if (ret == -1) { perror ("connect"); return -1; } printf ("成功连上服务器\n"); ask_server(socketfd); // 关闭套接字 close(socketfd); return 0;}
服务器端代码:
#include <sys/types.h>#include <sys/socket.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <arpa/inet.h>#include <pthread.h>#define PORT 9999struct User{ char name[20]; // 用户名 int socket; // 和用户通信的socket};// 协议struct Msg{ char msg[1024]; // 消息内容 char toname[20]; char fromname[20]; int cmd; // 消息类型};struct User user[20];// 初始化套接字,返回监听套接字int init_socket(){ //1、创建socket int listen_socket = socket(AF_INET, SOCK_STREAM, 0); if (listen_socket == -1) { perror ("socket"); return -1; } // 2、命名套接字,绑定本地的ip地址和端口 struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; // 设置地址族 addr.sin_port = htons(PORT); // 设置本地端口 addr.sin_addr.s_addr = htonl(INADDR_ANY); // 使用本地的任意IP地址 int ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr)); if (ret == -1) { perror ("bind"); return -1; } // 3、监听本地套接字 ret = listen(listen_socket, 5); if (ret == -1) { perror ("listen"); return -1; } printf ("等待客户端连接.......\n"); return listen_socket;}// 处理客户端连接,返回与连接上的客户端通信的套接字int MyAccept(int listen_socket){ // 4、接收连接 // 监听套接字不能用来与客户端进行通信,它的职责是监听客户端的连接 // accpet 处理客户端的连接,如果成功接收,会返回一个新的套接字,用来与客户端进行通信 // accept的第三个参数 是一个传入传出参数 struct sockaddr_in client_addr; // 用来保存客户端的ip和端口信息 int len = sizeof(client_addr); int client_socket = accept(listen_socket, (struct sockaddr *)&client_addr, &len); if (client_socket == -1) { perror ("accept"); } printf ("成功接收一个客户端: %s\n", inet_ntoa(client_addr.sin_addr)); return client_socket;}void reg(int client_socket, struct Msg *msg){ printf ("%s 进行注册\n", msg->msg); //客户端的整个结构体都发过来了,在服务器端的功能 函数读取之后也是读取的整个结构体(客户端,服务器端的结构体格式要一模一样); // 将用户进行保存 int i = 0; for (i = 0; i < 20; i++) { if (user[i].socket == 0) //收到客户端注册要求,就保存发送消息的客户端的套接字; { strcpy (user[i].name , msg->msg); user[i].socket = client_socket; break; } } if (i == 20) { msg->cmd = -1; } else { msg->cmd = 1001; //注意,注册的时候你服务器端得要返回一个消息给客户端来告诉他你的注册成功了; } write (client_socket, msg, sizeof(struct Msg));}// 群发void chat(int client_socket, struct Msg *msg){ printf ("%s 发一次群消息\n", msg->msg); // 筛选可以收消息的用户; int i = 0; for (i = 0; i < 20; i++) { if (user[i].socket != 0) { write (user[i].socket, msg, sizeof(struct Msg)); } }}// 私聊void chat2(int client_socket, struct Msg *msg){ printf ("%s 要 给 %s 发一条消息\n", msg->fromname, msg->toname); // 查找用户 int i = 0; for (i = 0; i < 20; i++) { if (user[i].socket != 0 && strcmp(user[i].name, msg->toname)==0) { write (user[i].socket, msg, sizeof(struct Msg)); break; } }}// 把 负责处理客户端通信的函数改成线程的工作函数void* hanld_client(void* v){ int client_socket = (int)v; struct Msg msg; while(1) { // 从客户端读一个结构体数据 int ret = read(client_socket, &msg, sizeof(msg)); if (ret == -1) { perror ("read"); break; } // 代表客户端退出 if (ret == 0) { printf ("客户端退出\n"); break; } switch (msg.cmd) { case 1 : // 客户但进行注册 reg(client_socket, &msg); break; case 2 : // 客户端进行聊天 chat(client_socket, &msg); break; case 3 : // 客户端进行私聊 chat2(client_socket, &msg); break; } } close (client_socket);}int main(){ // 初始化套接字 int listen_socket = init_socket(); while (1) { // 获取与客户端连接的套接字 int client_socket = MyAccept(listen_socket); // 创建一个线程去处理客户端的请求,主线程依然负责监听 pthread_t id; pthread_create(&id, NULL, hanld_client, (void *)client_socket); pthread_detach(id); // 线程分离 } close (listen_socket); return 0;}
阅读全文
0 0
- 【聊天室】android 简单的聊天室
- 简单的java聊天室
- unity3D简单的聊天室
- unity3D简单的聊天室
- 简单的聊天室制作
- 简单聊天室的实现
- java简单的聊天室
- 简单的网络聊天室
- 简单聊天室的代码
- 一个简单的聊天室
- 简单的聊天室
- 简单的网络聊天室
- 简单聊天室的编写
- 一个简单聊天室的建立
- Application对象 简单的聊天室
- 一个简单的聊天室程序
- ICE:实现简单的聊天室
- 简单的C/S聊天室
- cdq分治
- [转]vim——打开多个文件、同时显示多个文件、在文件之间切换
- TCP连接的建立与终止
- java获取键盘输入流
- Codeforces Round #330 (Div. 2)C. Warrior and Archer【博弈+逆向思维】
- 简单的聊天室
- 二叉树平衡检查(递归思想分析)
- 腾讯云系列一:Centos7安装 Oracle 11g EX 远程连接 超简单哦!
- C++中的指针数组与数组指针
- 画地为Mask,随心所欲的高效遮罩组件[Unity]
- Linux进程入门学习(六)-管道通信
- datastage Transformation函数之INDEX
- Java——Java集合Queue
- JDK下载安装以及环境变量配置图文详解【转】