Linux C语言 30-套接字操作

Linux C语言 30-套接字操作

本节关键字:C语言 网络通信、套接字操作、TCP、UDP、服务端、客户端
相关C库函数:socket, bind, listen, accept, setsockopt, recv, send, recvfrom, sendto, close

什么是网络通信?

通信是人与人之间通过某种媒体进行的信息交流与传递。网络是用物理链路将各个孤立的工作站或主机相连在一起,组成的数据链路。通信网络是指将各个孤立的设备进行物理连接,实现人与人,人与计算机,计算机与计算机之间进行信息交换的链路,从而达到资源共享和通信的目的。
在编程过程中,设计网络通信时一般只考虑两个对象:“服务端”和“客户端”。服务端与客户端可以存活于相同主机,也可以存活在不同主机。在服务端与客户端的通信中需要使用到套接字。那么套接字(socket)到底什么是呢?

什么是套接字?

“socket”直译为“插座”。从抽象层面看,服务端就好比插座,客户端就好比插头,二者之间是紧密联系的。套接字分为三类:

  • 流套接字(SOCK_STREAM)
    流套接字用于提供面向连接、可靠的数据传输服务,该服务保证数据能够实现无差错、无重复发送,并按照顺序接受。流套接字之所以能偶实现可靠的数据服务,原因在于使用了TCP传输控制协议。
  • 数据报套接字(SOCK_DGRAM)
    数据包套接字提供了一种无连接的服务,该服务不能保证数据传输的可靠性,数据有可能在传输过程中丢失或者出现数据重复,且无法保证顺序的接受数据。数据报套接字使用UDP进行数据传输。
  • 原始套接字(SOCK_RAW)
    原始套接字允许对较低层次的协议直接访问,常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为器可以自如控制Window下的多种协议,能够对网络地城的传输机制进行控制,所以可以应用原始套接字来操纵网络层和传输层应用。如:通过原始套接字接受发向本机的ICMP、IGMP,或者接受TCP/IP栈不能处理的IP包。

套接字通常由三个参数构成:IP地址、端口号和传输层协议。在C语言中主要有两类套接字通信:“TCP通信”和“UDP通信”。在实际编程时,通常会使用struct sockaddr和struct sockaddr_in两种数据类型来保存套接字信息。

// 大部分情况作为bind、connect、recvfrom、sendto等函数的参数进行传递,指明地址信息。在实际编程中,一般不对此结构体进行直接操作,而是使用sockaddr_in代替。
struct sockaddr
{
	sa_family_t     sa_family;    	// 地址族
	char            sa_data[14];    // 地址和端口号
};

struct sockaddr_in
{
	short int sin_family;         // 地址族
	unsigned short int sin_port;  // 端口号
	struct in_addr sin_addr;      // 地址
	unsigned char sin_zero[8];    // 8字节数组,全为0,该字节数组的作用是为了让两种数据结构大小相同而保留的空字节
};

// 两种数据结构中,地址族都占用两个字节,常见的地址族为:AF_INET、AF_INET6、AF_LOCAL。
// 值得注意的是网络编程中的字节序问题,建议使用C库中的相关函数对端口和地址进行字节序处理:
#include 
typedef unsigned short   uint16_t;
typedef unsigned long    uint32_t;

uint16_t htons(uint16_t bost16bit);  // 将一个主机字节顺序的无符号短整型数转换成网络字节顺序
uint32_t htonl(uint32_t bost32bit);  // 将一个主机字节顺序的无符号长整型数转换成网络字节顺序
uint16_t ntons(uint16_t net16bit);   // 将一个无符号短整型数从网络字节顺序转换为主机字节顺序
uint32_t ntonl(uint32_t net32bit);   // 将一个无符号长整型数从网络字节顺序转换为主机字节顺序

C语言网络编程之TCP通信

TCP通信相关库函数
TCP套接字参数设置
// 套接字参数设置
#include 
#include 
// 设置套接字参数,成功返回0,失败返回-1并且设置error
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
// 获取套接字参数,成功返回0,失败返回-1并且设置error
int getsockopt(int sockfd, int level, int optname, const void *optval, socklen_t *optlen);
/*
sockfd: 由socket()函数返回的套接字描述符
level: SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP、IPPROTO_IPV6
optname: 可用选项 SO_DEBUF、SO_DONTROUTE、SO_KEEPALIVE、SO_LINGER、SO_OOBINLINE、
SO_RCVBUG、SO_RCVLOWAT、SO_REUSEADDR、SO_SNDBUF、SO_SNDLOWAT、TCP_MAXSEG等
optval: 指针,指向存放选项值的缓冲区
optlen: optval缓冲区的长度
*/
// 设置端口复用(必须在bind()函数之前设置),对应重启程序后出现端口绑定失败的场景
int reuse = 1; // 默认为0,不启用端口复用
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void*)&reuse, sizeof(int));

// 设置收发超时时间,对应由于网络原因导致send()或recv()执行异常而发生阻塞的场景
int timeout = 1000; // 1秒
// 发送时限
setsockopt(socket, SOL_S0CKET, SO_SNDTIMEO, (const void*)&timeout, sizeof(int));
// 接收时限
setsockopt(socket, SOL_S0CKET, SO_RCVTIMEO, (const void*)&timeout, sizeof(int));

// 设置缓冲区大小,对应由于缓冲区爆满导致send()函数执行异常而发生阻塞的场景
// 值得注意的是:并不是说你设置的多大,系统就会设置多大,系统一般会将我们设置的缓冲区大小加倍,并且不得小于tcp的接收缓冲区和发送缓冲区设置的默认最小值。
// TCP有发送缓冲区和接收缓冲区,但是UDP因为是不可靠的,它没有确认重传机制,不保存应用程序数据的副本,所以是没有发送缓冲区的,但是UDP有接收缓冲区。
int buflen = 32*1024; // 32K
// 接收缓冲区
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (const void*)&buflen, sizeof(int));
// 发送缓冲区
setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (const void*)&buflen, sizeof(int));

// 优化由系统缓冲区到socket缓冲区拷贝过程对程序性能的影响
int zero=0;
setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (const void*)&zero, sizeof(int));
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (const void*)&zero, sizeof(int));

// 在UDP数据通信时,设置socket发送的数据具有广播特性
int broad = 1;
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const void*)&broad, sizeof(int));

// 设置心跳检测
int opt = 1;
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeog(int));

// 延迟接收,当接收到第一条数据之后再创建连接。对于http类非交互式的服务器很有意义,可以防御空连接攻击
int val = 5;
setsockopt(socket, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof(int));
TCP服务端和客户端共用
// TCP服务端和客户端共用
#include 
#include 
#include 

// 创建一个指定类型的套接字,成功返回套接字,失败返回-1并设置错误码error
// domain 指定通信域,选择用于通信的协议族,这些协议族在中定义
//    名称            		描述                    					说明
//    AF_UNIX, AF_LOCAL   Local communication             	本地通信协议
//    AF_INET            	IPv4 Internet protcaols         	IPv4互联网协议
//    AF_INET6        		IPv6 Internet protcaols         	IPv6互联网协议
//    AF_IPX            	IPX - Novell protocols          	IPX-Novell协议
//    AF_NETLINK        	Kernel user interface device    	内核用户接口设备协议
//    AF_X25            	ITU-T X.25 / ISO-8202 protocal  	ITU-T X.25/ISO-82208协议
//    AF_AX25            	Amater redio AX.25 protocol    	业余无线电AX.25协议
//    AF_ATMPVC        		Access to raw ATM PVCs          	访问原始ATM PVC
//    AF_APPLETALK        Appletalk                 			由Apple公司创建的一组网络协议
//    AF_PACKET        		Low level packet interface      	低级数据包接口
// type 套接字类型        
//    SOCK_STREAM        	提供有序、可靠、双向、基于连接的字节流,可以支持带外数据传输机制
//    SOCK_DGRAM        	支持数据报(固定最大长度的无连接、不可靠的消息)
//    SOCK_SEQPACKET     	为固定最大长度的数据报提供一条有序、可靠、双向连接的数据传输路径;消费者需要用每个输入系统调用读取这个数据报
//    SOCK_RAW       			提供原始网络协议访问
//    SOCK_RDW        		提供不保证排序的可靠数据报层
//    SOCK_PACKET        	已过时,不应在新程序中使用
// protocol 指定与套接字一起使用的特定协议。在给定的协议族中,通常只有一个协议支持特定的套接字类型,这种情况下protocol可以为0;也有存在很多协议的情况,此时protocol必须指定特定的协议
// error 错误码
//    EACCES            	创建指定类型和/或协议的套接字的权限被拒绝。
//    EAFNOSUPPORT        该实现不支持指定的地址系列。
//    EINVAL            	未知协议或协议系列不可用。类型中的标志无效。
//    EMFILE            	进程文件表溢出。已达到系统对打开文件总数的限制。
//    ENOBUFS or ENOMEM  	可用内存不足。在释放足够的资源之前,无法创建套接字。
//    EPROTONOSUPPORT     此域中不支持协议类型或指定的协议。
int socket(int domain, int type, int protocol);

// recv()从已连接的套接字读取数据,与src_addr为NULL的recvfrom()相同
// 成功返回读取消息的长度,如果消息太长导致无法放入所提供的缓冲区,则可能会丢弃多余的字节,具体取决于接收消息的套接字类型
// 如果套接字上没有可读的消息,recv将阻塞等待消息到达。若套接字是非阻塞的将返回-1,此时error被设置为EAGIN或EWOULDBLOCK
// 注意:读取套接字通常会返回任何可用的数据,而不是等待到请求的全部数据,这就导致可能出现数据包分帧的情况
// flags参数一般设置为0,也可通过对以下一个或多个值进行“或”运算形成:
//    MSG_CMSG_CLOEXEC    	使用SCM_RIGHTS操作,为通过UNIX域文件描述符接收的文件描述符设置关闭exec标志。
//    MSG_DONTWAIT        	启用非阻塞操作;如果操作将被阻止,则调用将失败,并显示错误EAGAIN或EWOULDBLOCK(也可以使用带有F_SETFL的O_NONBLOCK标志来启用fcntl(2))。
//    MSG_ERRQUEUE			此标志指定应从套接字错误队列接收排队的错误。错误在类型取决于协议的辅助消息中传递(对于IPv4IP_RECVERR)。用户应提供足够大小的缓冲区。
//    MSG_OOB            	该标志请求接收在正常数据流中不会接收到的带外数据。一些协议将加急数据放在正常数据队列的头部,因此该标志不能与此类协议一起使用。
//    MSG_PEEK        		此标志使接收操作从接收队列的开头返回数据,而不从队列中删除该数据。因此,随后的接收呼叫将返回相同的数据。
//    MSG_TRUNC (since Linux 2.2)    对于raw(AF_PACKET)、Internet数据报(自Linux 2.4.27/2.6.8起)、netlink(自Linux 2.6.22起)和UNIX数据报(从Linux 3.4起)套接字:返回数据包或数据报的实际长度,即使它比传递的缓冲区长。未针对UNIX域(UNIX(7))套接字实现。有关与Internet流套接字一起使用的信息,请参阅tcp(7)。
//    MSG_WAITALL (since Linux 2.2)    该标志请求操作块,直到完全请求得到满足为止。然而,如果捕捉到信号、发生错误或断开连接,或者下一个要接收的数据与返回的数据类型不同,则调用返回的数据可能仍然少于请求的数据。
//    MSG_EOR            表示记录结束;返回的数据完成了一个记录(通常与类型为SOCK_SEQPACKET的套接字一起使用)。
//    MSG_TRUNC        指示数据报的尾部被丢弃,因为数据报大于所提供的缓冲区。
//    MSG_CTRUNC        指示一些控制数据由于缓冲器中用于辅助数据的空间不足而被丢弃。
//    MSG_OOB            以指示已接收到加急或带外数据。
//    MSG_ERRQUEUE        指示未接收到任何数据,但接收到来自套接字错误队列的扩展错误。
// error 错误码类型
//    EAGAIN或者EWOULDBLOCK    套接字设置为非阻塞,但所请求的操作需要阻塞;套接字被标记为非阻塞,接收操作将被阻塞,或者设置了接收超时,并且在接收数据之前超时已过期。POSIX.1-2001允许在这种情况下返回任何一个错误,并且不要求这些常量具有相同的值,因此便携式应用程序应该检查这两种可能性。
//    EBADF            指定了非法套接字描述符
//    ECONNREFUSED        远程主机拒绝允许网络连接(通常是因为它没有运行请求的服务)
//    EFAULT            参数指定的用户地址空间非法
//    EINTR            接收到信号
//    EINVAL            传递的参数非法
//    ENOMEM            没有可用内存
//    ENOTCONN        套接字与面向连接的协议相关联,并且尚未连接
//    ENOTSOCK        参数sockfd不是一个套接字
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

// send()从已连接的套接字读取数据。成功返回读取的字节数,失败返回-1并设置error
// flags一般为0,也可包含下列标志:
//    MSG_CONFIRM        (仅用于Linux 2.3以上版本)通知链路层发生了转发过程:得到了另一端的成功应答.如果链路层没有收到通知,它将按照常规探测网络上的相邻主机(比如通过免费arp).只能用于SOCK_DGRAM和SOCK_RAW类型的套接字,且仅对IPv4和IPv6有效.详情参见 arp(7)
//    MSG_DONTROUTE        在送出分组时不使用网关,只有直接连接在网络上的主机才能接收到数据。这个标志通常仅用于诊断和路由程序,路由的协议族才能使用这个标志;套接字不可以。
//    MSG_DONTWAIT        使用非阻塞式操作;如果操作需要阻塞,将返回 EAGAIN 错误(也可以用 F_SETFL fcntl(2) 设置 O_NONBLOCK 实现这个功能.)
//    MSG_EOR (since Linux 2.2)
    终止记录(当支持此概念时,如SOCK_SEQPACKET类型的套接字)。

//    MSG_MORE (Since Linux 2.4.4)    呼叫者还有更多数据要发送。此标志与TCP套接字一起使用,以获得与TCP_CORK套接字选项相同的效果(请参阅TCP(7)),不同之处在于此标志可以在每次调用的基础上设置。自Linux 2.6以来,UDP套接字也支持此标志,并通知内核将设置了此标志的调用中发送的所有数据打包为单个数据报,该数据报仅在执行未指定此标志的呼叫时发送。(另请参阅UDP(7)中描述的UDP_CORK套接字选项)。
//    MSG_NOSIGNAL        当流式套接字的另一端中断连接时不发送 SIGPIPE 信号,但仍然返回 EPIPE 错误.
//    MSG_OOB
            在支持此概念的套接字上发送带外数据(例如,类型为SOCK_STREAM);底层协议还必须支持带外数据。
// error 错误码类型
//    EACCES            (对于由路径名标识的UNIX域套接字)目标套接字文件的写入权限被拒绝,或者路径前缀的某个目录的搜索权限被拒绝。(对于UDP套接字)试图将其发送到网络/广播地址,就好像它是单播地址一样。
//    EAGAIN或者EWOULDBLOCK    套接字设置为非阻塞,但所请求的操作需要阻塞
//    EBADF            指定了非法套接字描述符
//    ECONNRESET        对等方重置连接。
//    EDESTADDRREQ        套接字不是连接模式,并且没有设置对等地址。
//    EFAULT            参数指定的用户地址空间非法
//    EINTR            接收到信号
//    EINVAL            传递的参数非法
//    EISCONN            连接模式套接字已连接,但指定了收件人。(现在,要么返回此错误,要么忽略收件人规范。)
//    EMSGSIZE        消息长度越界,套接字类型要求以原子方式发送消息,而要发送的消息的大小使得这不可能实现
//    ENOBUFS            网络接口输出队列已满,这通常表明接口已停止发送,也有可能是暂时性的拥挤(这不会发生在linux下,当设备队列溢出时数据报只是被简单的丢弃)
//    ENOMEM            没有可用内存
//    ENOTCONN        套接字未连接,也未给定目标
//    ENOTSOCK        参数sockfd不是一个套接字        
//    EOPENOTSUPP        flags参数中的某些位不适合套接字类型
//    EPIPE            连接套接字的本地端已关闭,这种情况下进程还会接收到SIGPPIPE信号,除非设置了MSG_NONSIGNAL
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

// 关闭文件描述符
int close(int fd);
TCP服务端使用
// TCP服务端使用
#include 
#include 
// 为套接字sockfd指定本地地址addr,传统的叫法是给一个套接字分配一个名字。使用socket()函数创建一个套接字时,它存在一个地址空间(地址表),但还没有给它分配一个名字
// 成功返回0,失败返回-1并设置错误码error
// error 错误码类型:
//    EBADF            sockfd 不是一个合法套接字描述符.
//    EINVAL            套接字已经绑定到一个地址.这一条在以后会有所改变: 具体参见 linux/unix/sock.c
//    EACCES            地址受保护,用户不是系统管理员.
//    ENOTSOCK
        参数是文件描述符,不是一个套接字.
// 下列错误适用于UNIX域 (AF_UNIX) 套接字.
//    EINVAL            地址长度 addrlen 错误,或者套接字不在 AF_UNIX 族.
//    EROFS            套接字节点位于只读文件系统.
//    EFAULT             参数addr 指向用户无权访问的地址空间.
//    ENAMETOOLONG
        参数addr 长度超范围.
//    ENOENT            文件不存在.
//    ENOMEM            内核存储空间不足.
//    ENOTDIR
            指定路径不是一个目录.
//    EACCES            指定路径拒绝访问.
//    ELOOP            在解析 my_addr 时发现过多符号连接.
int bind(int sockfd, const struct sockaddr *addr, socklen_t addlrlen);

// 在接收连接之前,首先要使用socket()创建一个套接字,然后调用listen()使其能够自动接收到来的连接并且为连接队列指定一个长度限制.之后就可以使用accept()接收连接.listen()调用仅适用于SOCK_STREAM或者SOCK_SEQPACKET类型的套接字.
// 成功返回0,错误返回-1并设置错误码error
// 参数backlog指定未完成连接队列的最大长度.如果一个连接请求到达时未完成连接队列已满,那么客户端将接收到错误ECONNREFUSED.或者,如果下层协议支持重发,那么这个连接请求将被忽略,这样客户端在重试的时候就有成功的机会.
// error 错误码类型:
//    EBADF            参数 s 不是合法的描述符.
//    ENOTSOCK
        参数 s 不是一个套接字.
//    EOPNOTSUPP
        套接字类型不支持 listen 操作.
int listen(int sockfd, int backlog);

// accept()函数用于基于连接的套接字(SOCK_STREAM, SOCK_SEQPACKET 和 SOCK_RDM).它从未完成连接队列中取出第一个连接请求,创建一个和参数sockfd属性相同的连接套接字,并为这个套接字分配一个文件描述符,
然后以这个描述符返回.新创建的描述符不再处于监听状态.原套接字socket不受此调用的影响.注意任意一个文件描述符标志(任何可以被fcntl以参数 F_SETFL 设置的值,比如非阻塞式或者异步状态)不会被accept. 所继承.
// 参数sockfd是以socket()函数创建,用bind()函数绑定到一个本地地址,并且在调用了listen()函数进行监听的套接字.
// 参数addr是一个指向结构sockaddr的指针.这个结构体以连接实体地址填充.所谓的连接实体,就是众所周知的网络层.参数 addr 所传递的真正的地址格式依赖于所使用的套接字族.(参见 socket(2) 和各协议自己的手册页).
// 参数addrlen是一个实时参数:  它的大小应该能够足以容纳参数
addr 所指向的结构体;在函数返回时此参数将以字节数表示出返回地址的 实际长度.若 addr 使用NULL作为参数,addrlen将也被置为NULL.
// 如果队列中没有未完成连接套接字,并且套接字没有标记为非阻塞式, accept 将阻塞直到一个连接到达.如果一个套接字被标记为非阻塞式而队列 中没有未完成连接套接字, accept 将返回EAGAIN.
// 成功返回一个新的套接字,失败返回-1并设置错误码error
// error 错误码类型:
//    EAGAIN或者EWOULDBLOCK    套接字被标记为非阻塞,且当前没有可接收的连接.
//    EBADF            描述符非法.
//    ENOTSOCK
        描述符指向一个文件,而不是一个套接字.
//    EOPNOTSUPP
        作为参数的套接字不是 SOCK_STREAM.类型
//    EFAULT            参数 addr 不在用户可写地址空间之内.
//    EPERM            防火墙规则禁止连接.
//    ENOBUFS,ENOMEM        没有足够内存.  这个错误一般来说意味着内存分配受套接字缓冲区所限, 而不是没有系统内存.
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
TCP客户端使用
// TCP客户端使用
#include 
#include 
// 将文件描述符sockfd引用的套接字连接到addr指定的地址。addrlen指定addr的大小,addr中地址的格式由套接字sockfd的地址空间决定
// 如果套接字sockfd的类型是SOCK_DGRAM,那么addr是默认情况下发送数据报的地址,也是接收数据报的唯一地址。如果套接字的类型是SOCK_STREAM或SOCK_SEQPACKET,则此调用将尝试连接到绑定到addr指定地址的套接字。
// 通常,基于连接的协议套接字可能只成功connect()一次;无连接协议套接字可以多次使用connect()来更改其关联。无连接套接字可以通过连接到sockaddr的sa_family成员设置为AF_UNSPEC(自内核2.2以来在Linux上受支持)的地址来解除关联。
// 成功返回0,失败返回-1并设置错误码error
// error 错误码类型:
//    EACCES             对于由路径名标识的UNIX域套接字:套接字文件的写入权限被拒绝,或者路径前缀中某个目录的搜索权限被拒绝。(另请参见path_resolution(7)。)
//    EACCES, EPERM        用户尝试在未启用套接字广播标志的情况下连接到广播地址,或者由于本地防火墙规则,连接请求失败。
//    EADDRINUSE        本地地址已在使用中。
//    EAFNOSUPPORT        传递的地址的sa_family字段中没有正确的地址族。
//    EADDRNOTAVAIL        请求的接口不存在,或者请求的地址不是本地地址。
//    EALREADY        套接字是非阻塞的,以前的连接尝试尚未完成。
//    EBADF              文件描述符不是描述符表中的有效索引。
//    ECONNREFUSED        没有人在监听远程地址。
//    EFAULT             套接字结构地址在用户的地址空间之外。
//    EINPROGRESS        套接字是非阻塞的,无法立即完成连接。可以通过选择写入套接字来select()或poll()以完成。在select()指示可写入性后,使用getsockopt(2)读取SOL_SOCKET级别的SO_ERROR选项,以确定connect()是否成功完成(SO_ERROR为零)或未成功(SO_ERROR是此处列出的常见错误代码之一,解释了失败的原因)。
//    EINTR              系统调用被捕获的信号中断;参见信号(7)。
//    EISCONN            套接字已连接
//    ENETUNREACH        网络无法访问
//    ENOTSOCK        文件描述符未与套接字关联。
//    ETIMEDOUT        尝试连接时超时。服务器可能太忙,无法接受新连接。请注意,对于IP套接字,当服务器上启用syncookies时,超时时间可能会很长。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
TCP通信服务端例程

Linux C语言 31-网络编程之TCP例程

TCP通信客户端例程

Linux C语言 31-网络编程之TCP例程

C语言网络编程之UDP通信

UDP通信相关库函数
#include 
#include 
// UDP服务端和客户端共用
// 同TCP部分解释
int socket(int damain, int type, int protocol);
// 从套接字接收消息和读取数据,套接字可以是面向连接的,也可以不是面向连接的
// 如果参数src_addr不为NULL,并且底层协议提供了源地址,则会填写此源地址。当src_addr为NULL时,则不填写任何内容;在这种情况下,不使用addrlen,也应该为NULL。
// 如果提供的缓冲区太小,则会截断返回的地址;在这种情况下,addrlen将返回一个大于提供给调用的值。
// 如果src_addr为NULL,使用方法和recv()一样
// 成功返回读取的字节数,失败返回-1,并设置错误码error(同TCP部分解释)
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

// 将消息传输到另一个套接字,如果在连接模式(SOCK_STREAM、SOCK_SEQPACKET)套接字上使用sendto(),则参数dest_addr和addrlen将被忽略(当它们不是NULL和0时,可能会返回错误EISCONN),而当套接字未实际连接时,则会返回错误ENOTCONN。否则,目标的地址由dest_addr给定,addrlen指定其大小。对于send()和sendto(),消息位于buf中,长度为len
// 成功返回发送字节数,失败返回-1并设置错误码error,错误码说明同TCP部分解释
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

#include 
// 关闭套接字
int close(int fd);

// UDP服务端使用
// 同TCP部分解释
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
UDP通信服务端例程

Linux C语言 32-网络编程之UDP例程

UDP通信客户端例程

Linux C语言 32-网络编程之UDP例程

你可能感兴趣的:(Linux_C语言,linux,c语言,网络,开发语言,服务器)