C语言多线程服务器的实现实例

论坛 期权论坛 脚本     
niminba   2021-5-23 04:58   1674   0

本文基于 C 标准库提供的网络通信 API,使用 TCP ,实现一个简单的多线程服务器 Demo 。

首先要看 API

API

字节序转换

函数原型:

#include <arpa/inet.h>
uint64_t htonll(uint64_t hostlonglong);
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint64_t ntohll(uint64_t netlonglong);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

h 表示 host, n 表示 network,这些函数的作用是把主机的字节序转换为网络的字节序(即小端到大端的转变)。

例如:

#include <arpa/inet.h>
#include <stdio.h>
int main()
{
 uint32_t host = 0x01020304; // high->low: 01 02 03 04
 uint32_t network = htonl(host); // high->low: 04 03 02 01
 printf("%p\n", network); // 0x4030201
}

socket

函数原型:

#include <sys/socket.h>
int socket(int domain, int type, int protocol);

建立一个协议族为 domain, 协议类型为 type, 协议编号为 protocol 的套接字文件描述符。如果函数调用成功,会返回一个标识这个套接字的文件描述符,失败的时候返回-1。

domain 的取值:

Name  Purpose    Man page
AF_UNIX, AF_LOCAL Local communication  unix(7)
AF_INET  IPv4 Internet protocols  ip(7)
AF_INET6  IPv6 Internet protocols  ipv6(7)
AF_IPX  IPX - Novell protocols
AF_NETLINK  Kernel user interface device netlink(7)
AF_X25  ITU-T X.25 / ISO-8208 protocol x25(7)
AF_AX25  Amateur radio AX.25 protocol
AF_ATMPVC  Access to raw ATM PVCs
AF_APPLETALK AppleTalk   ddp(7)
AF_PACKET  Low level packet interface packet(7)
AF_ALG  Interface to kernel crypto API

AF 是 Address Family 的缩写,INET 是 Internet 的缩写。某些地方可能会使用 PF,即 Protocol Family,应该是同一个东西。

type 的取值:

SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mechanism may be supported.

SOCK_DGRAM Supports datagrams (connectionless, unreliable messages of a fixed maximum length).

SOCK_SEQPACKET Provides a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a consumer is required to read an entire packet with each input system call.

SOCK_RAW Provides raw network protocol access.

SOCK_RDM Provides a reliable datagram layer that does not guarantee ordering.

SOCK_PACKET Obsolete and should not be used in new programs; see packet(7).

type 常用的是 STREAMDGRAM ,根据描述,可以确定前者对应 TCP,而后者对应 UDP :

  • SOCK_STREAM 套接字表示一个双向的字节流,与管道类似。流式的套接字在进行数据收发之前必须已经连接,连接使用 connect() 函数进行。一旦连接,可以使用 read() 或者 write() 函数进行数据的传输,流式通信方式保证数据不会丢失或者重复接收。
  • SOCK_DGRAMSOCK_RAW 这个两种套接字可以使用函数 sendto() 来发送数据,使用 recvfrom() 函数接受数据,recvfrom() 接受来自制定IP地址的发送方的数据。

对于第 3 个参数 protocal,用于指定某个协议的特定类型,即 type 类型中的某个类型。通常某协议中只有一种特定类型,这 样protocol 参数仅能设置为 0 ;但是有些协议有多种特定的类型,就需要设置这个参数来选择特定的类型。

bind

函数原型:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

如果函数执行成功,返回值为 0,否则为 SOCKET_ERROR

参数:

  • sockfd 是一个有效的 socket 描述符(函数 socket() 的有效返回值)。
  • addrlen 是第二个参数 addr 结构体的长度。
  • addr 是一个 sockaddr 结构体指针,包含 IP 和端口等信息。

sockaddr 的结构如下:

struct sockaddr {
 sa_family_t sa_family;
 char sa_data[14];
};
// sa_familt_t 是无符号整型,Ubuntu 下是 unsigned short int

sockaddr 的存在是为了统一地址结构的表示方法 ,统一接口函数,使得不同的地址结构可以被 bind(), connect(), recvfrom(), sendto() 等函数调用。但一般的编程中并不直接对此数据结构进行操作,而使用另一个与之等价的数据绑\IX Y[YK NBY[\ Y QKY[\ XY QNCBJ\IX NYJ\NXY] S NCBB[XZ[ CB[\[H] QU PSK N[\\\[[]]H Y\[ NXYYY[Z[HHQUYH NYYH SQJNBY [ \[  XY I[\[YJHOH LJCB\[\N^] LJNCBBY \[\[ UQUQJHOH LJCB\\[\N^] LJNCBB[H JCBXY \HX[[XYJN\IXHX\ \[  XY I[\\I [\\I[N []HX\  S S NXYYXYX]J [\Y S [WXY   ]\NXY]XY NCBJ\[ NO OB ]B Y[ σB]\HHBH\H\BYH [ YH \] YH \\\ YH ][] YH K] YH X YH [ YH \ BY[H \ \HL HB[XZ[ CB[H] QU PSK N[Y[]H Y NXYYY[Z[HHQUYH NYYH[]\ NBY X  XY I[\[XYJH  CB\X\N^] LJNCBB\YЕQKXYЕQN[H YQ[HOHS CBY  YWHOH CBXZBB  Y[YK N[Y[H \YNBX XYQ N[\\H \XYNBY[\ Y QKY[\ XY QNCBJ N^] NO OB ]B /c9 σB+& BB\[\ [XYBY[ [Y[ B Bab:/cO\ Od#/c9i&.*OY[ O B[OH^ X[Y\[Y[HZZ[Z[[^][K NKLLL NXX MYK Bg :)y#+9#ybyfj;k-+c9g*9d#9. 9.fj9."`9.-o9!T9+L H;i9 9iyj:ghg,9b#9n:+#yby/c9g*9. 9.*.y#ybyfj9."d#o 9/ c#9az/c9b Bb,9i:/l+ 9i&#ybyfj9kk/,y.,:/9&al+ 9i&#ybyfj9kaykz+'9c..cy%c"9al#9&.#i&i&+/c.

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP