缩短链接的网站,网络营销顾问培训,够完美网站建设,wordpress中文团队源码#xff1a;https://github.com/antirez/smallchat 可用于学习网络通信#xff0c;源码很小。
考虑先基于第一版进行分析#xff1a; https://github.com/antirez/smallchat/blob/Episode-1/smallchat.c
先给出readme文件的翻译#xff1a; Smallchat TLDR: 这只是一…源码https://github.com/antirez/smallchat 可用于学习网络通信源码很小。
考虑先基于第一版进行分析 https://github.com/antirez/smallchat/blob/Episode-1/smallchat.c
先给出readme文件的翻译 Smallchat TLDR: 这只是一个我为几位朋友提供的编程示例。我上传了一个视频到我的YouTube频道放大了代码以查看从这个如此简单且故意破碎的示例中可以学到什么。将会有更多的视频和改进详见本README文件末尾。
现在让我来讲述完整的故事
昨天我与我的几位朋友交谈他们大多是前端开发者对系统编程有些距离。我们在回忆IRC的旧时光。不可避免地我说编写一个非常简单的IRC服务器是每个人都应该做的经历我向他们展示了我用TCL编写的实现我很震惊我18年前就写了它时间过得真快。像那样的程序中有一些非常有趣的部分。一个进程执行多路复用获取客户端状态并在客户端有新数据时尝试快速访问这种状态等等。
但后来讨论演变我想我来展示一个非常简单的C语言示例给你们看。你能写出最小的聊天服务器是什么样的首先要真正简化我们不应该要求任何正式的客户端。即使不太完善它应该能够与telnet或ncnetcat一起使用。服务器的主要操作只是接收一些聊天行并将其发送给所有其他客户端有时被称为扇出操作。但是这将需要一个适当的readline()函数然后进行缓冲等等。我们希望它更简单让我们使用内核缓冲区来欺骗假装我们每次都从客户端接收到一个完整形式的行在实践中这种假设通常成立所以事情有点能用。
好吧通过这些技巧我们可以实现一个聊天甚至可以让用户在只有200行代码的情况下设置他们的昵称当然要删除空格和注释。由于我将这个小程序作为给我的朋友的示例我决定也将其推送到Github上。
未来的工作 在接下来的几天里我将继续修改这个程序以发展它。不同的演变步骤将根据我关于编写系统软件系列的YouTube剧集中的更改进行标记。这是我的计划可能会改变但大致上这是我想要涵盖的内容
实现读写缓冲。避免线性数组使用字典数据结构来保存客户端状态。编写一个适当的客户端能够处理异步事件的行编辑。实现频道。从select(2)切换到更高级的API。为聊天实现简单的对称加密。
不同的更改将由一个或多个YouTube视频进行介绍。完整的提交历史将保存在这个存储库中。
下面是第一版的源码后面会与第二版源码进行对比说明 smallchat.c – 读取客户端输入发送给所有其他连接的客户端。 数据结构最小化且简单。实际核心就一个chatState对象Chat。
#define MAX_CLIENTS 1000 // This is actually the higher file descriptor. 客户端总数限制
#define SERVER_PORT 7711 //服务器端口
/* This structure represents a connected client. There is very little* info about it: the socket descriptor and the nick name, if set, otherwise* the first byte of the nickname is set to 0 if not set.* The client can set its nickname with /nick nickname command. */
struct client {int fd; // Client socket. 客户端的套接字描述符用于与客户端通信。char *nick; // Nickname of the client. 客户名默认为0
};
/* This global structure encasulates the global state of the chat. 封装聊天程序的全局状态信息。*/
struct chatState {int serversock; // Listening server socket. 服务器的监听套接字用于接受客户端连接请求。int numclients; // Number of connected clients right now.当前连接的客户端数量。int maxclient; // The greatest clients slot populated.最大的 clients 槽位被占用的索引。struct client *clients[MAX_CLIENTS]; // Clients are set in the corresponding slot of their socket descriptor.客户端数组用于存储连接到服务器的客户端信息。每个客户端通过其套接字描述符在数组中找到对应的位置。
};
struct chatState *Chat; // Initialized at startup.指向 struct chatState 结构的指针用于表示整个聊天程序的全局状态。在程序启动时会初始化该结构。api最基本的socket 我调整一下学习顺序从低到高按被调用顺序看
先看内存申请。其实只是为了在内存不足时先输出错误信息并正常退出返回1避免崩溃
/* We also define an allocator that always crashes on out of memory: you* will discover that in most programs designed to run for a long time, that* are not libraries, trying to recover from out of memory is often futile* and at the same time makes the whole program terrible. */
void *chatMalloc(size_t size) {void *ptr malloc(size);if (ptr NULL) {perror(Out of memory);exit(1);}return ptr;
}
/* Also aborting realloc(). */
void *chatRealloc(void *ptr, size_t size) {ptr realloc(ptr,size);if (ptr NULL) {perror(Out of memory);exit(1);}return ptr;
}初始化全局的唯一的数据结构对象创建tcp服务器
/* Create a TCP socket lisetning to port ready to accept connections. */
int createTCPServer(int port) {int s, yes 1;struct sockaddr_in sa;if ((s socket(AF_INET, SOCK_STREAM, 0)) -1) return -1;setsockopt(s, SOL_SOCKET, SO_REUSEADDR, yes, sizeof(yes)); // Best effort.memset(sa,0,sizeof(sa));sa.sin_family AF_INET;sa.sin_port htons(port);sa.sin_addr.s_addr htonl(INADDR_ANY);if (bind(s,(struct sockaddr*)sa,sizeof(sa)) -1 ||listen(s, 511) -1){close(s);return -1;}return s;
}
/* Allocate and init the global stuff. */
void initChat(void) {Chat chatMalloc(sizeof(*Chat));memset(Chat,0,sizeof(*Chat));/* No clients at startup, of course. */Chat-maxclient -1;Chat-numclients 0;/* Create our listening socket, bound to the given port. This* is where our clients will connect. */Chat-serversock createTCPServer(SERVER_PORT); //创建tcp服务器if (Chat-serversock -1) {perror(Creating listening socket);exit(1);}
}