C语言实现简易client/server网络多人聊天工具

一、C语言实现一个简易的client/server聊天工具

  在ubuntu平台上,采用c语言实现一个简易的client/server聊天工具,思路是:

  服务器端:首先创建一个服务器进程,该进程监听客户端的连接,如果收到并建立连接后创建一个线程服务该客户端。该线程负责消息的转发(这里为了方便直接对消息进行广播)。

  客户端:客户端进程首先创建一个线程用于消息接收处理,然后为用户提供信息输入的交互界面。

  主要调用栈:

  int socket( int domain, int type, int protocol)

  • 功能:创建一个新的套接字,返回套接字描述符
  • 参数说明:
  • domain:域类型,指明使用的协议栈,如TCP/IP使用的是 PF_INET
  • type: 指明需要的服务类型, 如
  • SOCK_DGRAM: 数据报服务,UDP协议
  • SOCK_STREAM: 流服务,TCP协议
  • protocol:一般都取0
  • 举例:s=socket(PF_INET,SOCK_STREAM,0)

  int connect(int sockfd,struct sockaddr *server_addr,int sockaddr_len)

  • 功能: 同远程服务器建立主动连接,成功时返回0,若连接失败返回-1。
  • 参数说明:
  • Sockfd:套接字描述符,指明创建连接的套接字
  • Server_addr:指明远程端点:IP地址和端口号
  • sockaddr_len :地址长度

  int bind(int sockfd,struct sockaddr * my_addr,int addrlen)

  • 功能:为套接字指明一个本地端点地址TCP/IP协议使用sockaddr_in结构,包含IP地址和端口号,服务器使用它来指明熟知的端口号,然后等待连接
  • 参数说明:
  • Sockfd:套接字描述符,指明创建连接的套接字
  • my_addr:本地地址,IP地址和端口号
  • addrlen :地址长度
  • 举例:bind(sockfd, (struct sockaddr *)&address, sizeof(address));

  int listen(int sockfd,int input_queue_size)

  • 功能:
  • 面向连接的服务器使用它将一个套接字置为被动模式,并准备接收传入连接。用于服务器,指明某个套接字连接是被动的
  • 参数说明:
  • Sockfd:套接字描述符,指明创建连接的套接字
  • input_queue_size:该套接字使用的队列长度,指定在请求队列中允许的最大请求数
  • 举例:listen(sockfd,20)

  int accept(int sockfd, void *addr, int *addrlen);

  • 功能:获取传入连接请求,返回新的连接的套接字描述符。为每个新的连接请求创建了一个新的套接字,服务器只对新的连接使用该套接字,原来的监听套接字接受其他的连接请求。新的连接上传输数据使用新的套接字,使用完毕,服务器将关闭这个套接字。
  • 参数说明:
  • Sockfd:套接字描述符,指明正在监听的套接字
  • addr:提出连接请求的主机地址
  • addrlen:地址长度
  • 举例:new_sockfd = accept(sockfd, (struct sockaddr *)&address, &addrlen);

  int send(int sockfd, const void * data, int data_len, unsigned int flags)

  • 功能:在TCP连接上发送数据,返回成功传送数据的长度,出错时返回-1。send会将外发数据复制到OS内核中
  • 参数说明:
  • sockfd:套接字描述符
  • data:指向要发送数据的指针
  • data_len:数据长度
  • flags:一直为0
  • 举例(p50):send(s,req,strlen(req),0);

  int recv(int sockfd, void *buf, int buf_len,unsigned int flags);

  • 功能:从TCP接收数据,返回实际接收的数据长度,出错时返回-1。服务器使用其接收客户请求,客户使用它接受服务器的应答。如果没有数据,将阻塞,如果收到的数据大于缓存的大小,多余的数据将丢弃。
  • 参数说明:
  • Sockfd:套接字描述符
  • Buf:指向内存块的指针
  • Buf_len:内存块大小,以字节为单位
  • flags:一般为0
  • 举例:recv(sockfd,buf,8192,0)

  close(int sockfd);

  • 功能:撤销套接字。如果只有一个进程使用,立即终止连接并撤销该套接字,如果多个进程共享该套接字,将引用数减一,如果引用数降到零,则撤销它。
  • 参数说明:
  • Sockfd:套接字描述符
  • 举例:close(socket_descriptor)

二、服务器端源代码:

 1 #include <stdio.h>
 2 #include <pthread.h>
 3 #include <string.h>
 4 #include <sys/types.h>
 5 #include <sys/socket.h>
 6 #include <netinet/in.h>
 7 #include <arpa/inet.h>
 8 #include <unistd.h> 
 9 
10 int client_sockfd[100] = {0};//客户端套接字
11 int count = 0;
12 
13 void* clientThreadLoop(void* local)
14 {
15     char buf[BUFSIZ];  //数据传送的缓冲区
16 
17     //printf("线程启动
");
18     int socket_id = *(int *)local;
19     while(1)
20     {
21         memset(buf,0x00,sizeof(buf));
22         int len=recv(socket_id,buf,BUFSIZ,0);
23         /*接收客户端的数据并将其发送给客户端--recv返回接收到的字节数,send返回发送的字节数*/
24         if(len > 0)
25         {
26             buf[len]='