socket 多线程聊天室的实现(C语言)

2019年6月25日 Jerry 10357 2020年12月3日

       人生不止眼前的苟且,代码也不止数据的增删改查,也有有趣的网络编程。如何用C语言做一个简单的服务器和客户端,实现一个聊天室程序呢?这里就简单的写一下博主的实现。

一、程序需求

实现一个简单的服务器,包括以下功能:

  • 可以监听并且与多个客户端建立TCP链接。
  • 可以接收客户端发来的消息,并发送给所有的客户端。
  • 可查询所有的客户端链接。

实现客户端有如下功能:

  • 输入服务器端口号,与服务器端建立链接。
  • 发送消息给服务器。
  • 接收并打印服务器发来的消息。

二、实现分析

       借用百度的一张图,这个流程很好的解释了socket编程的根本:

服务器端的处理流程思路:

  1. 创建socket套接字
  2. 绑定ip与端口号 
  3. 创建监听线程,等待客户端链接
  4. 接收到一个客户端链接则创建一个线程进行消息接收处理
  5. 客户端关闭,关闭相关进程
  6. 服务器关闭

客户端的处理流程思路:

  1. 创建socket套接字
  2. 输入端口号链接服务器
  3. 创建线程处理服务器消息
  4. 接收控制台输入发送给服务器
  5. 客户端关闭

socket的基本api:

      包含在在头文件“winsock2.h”,官网说明地址: https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/

三、基本的socket API

1、创建一个socket套接字:

/*
domain:协议域、地址域或协议族。常用的协议族有:AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX)、AF_ROUTE等等
type:socket类型。常用的socket类型有:SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等
protocol:指定使用的协议。常用的协议有:IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等等
返回值:成功返回一个非负整数的fd,失败则返回-1
*/
int socket(int domain, int type, int protocol);

2、绑定套接字

/*
sockfd:socket文件描述符,即socket()的返回值
addr:指向sock地址的指针
addrlen:sock地址的长度
返回值:成功返回0,失败返回-1
*/
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

3、监听套接字

/*
sockfd:被监听的套接字
backlog:最大等待队列数量
返回值:成功返回0,失败返回-1
*/
int listen(int sockfd, int backlog);

4、连接socket套接字

/*
sockfd:客户端的套接字
addr:服务器的地址
addrlen:服务器的地址的长度
返回值:成功返回0,失败返回-1
*/
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

5、接受socket连接请求

/*
sockfd:被监听的套接字
addr:返回客户端的地址,可为NULL
addrlen:指定客户端的地址的长度,可为NULL
返回值:成功返回已连接的新套接字描述符connfd,失败返回-1
*/
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

6、socket接收数据

/*
sockfd:从这个socket接收数据
buf:用来保存接收到的数据
len:指定buf的长度,表示最多接收这么多个字节的数据
flags:flags,指定对应的选项,一般置为0
返回值:成功返回接收到的数据大小,返回0表示对方不再发送数据(可以理解为关闭了连接),出错返回-1
*/
int recv(int sockfd, void *buf, int len, int flags);

7、socket发送数据

/*
sockfd:向这个socket发送数据
buf:发送buf指向的数据
len:指定buf的长度,指定要发送的数据大小
flags:flags,指定对应的选项,一般置为0
返回值:成功返回已发送的数据大小,失败则返回-1
*/
int send(int sockfd, void *buf, int len, int flags);

8、从udp socket接收数据

/*
sockfd:输入参数,从该socket接收数据
buf:输出参数,将接收的数据存放在buf上
len:输入参数,指定buf的长度
flags:输入参数,flags,指定对应的选项,一般置为0
addr:输出参数,保存该数据的发送方地址
addrlen:输入参数,指定发送方地址的长度
返回值:成功返回接收到的数据大小,失败则返回-1
*/
int recvfrom(int sockfd, void *buf, int len, int flags, struct sockaddr *addr, socklen_t *addrlen);

9、向udp socket发送数据

/*
sockfd:输入参数,向该socket发送数据
buf:输入参数,发送buf指向的数据
len:输入参数,指定buf的长度
flags:输入参数,flags,指定对应的选项,一般置为0
addr:输入参数,指定接收方的地址
addrlen:输入参数,指定接收方的地址的长度
返回值:成功返回发送的数据大小,失败则返回-1
*/
int sendto(int sockfd, void *buf, int len, int flags, struct sockaddr *addr, socklen_t addrlen);

10、关闭socket

/*
fd: 要关闭的socketID
*/
int close(int fd);

四、最终实现效果

服务器端:

客户端:

1、建立多个链接

2、发送消息

3、客户端断开链接

4、服务器关闭

 

       搞起!


原创文章,转载请注明出处: https://jerrycoding.com/article/socket-chat

微信
jerry微信赞助
支付宝
jerry支付宝赞助

您尚未登录,暂时无法评论。请先 登录 或者 注册

0 人参与 | 0 条评论