入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

Linux网络编程之基础API使用

创建时间:2018-01-14 投稿人: 头好痒是不是要长脑子了 浏览次数:174

Linux网络编程之基础API使用

在本地进程中,我们可以通过一个进程号(PID)来标记唯一进程,那么在网络中,很明显该方法不可以。其实TCP/IP协议栈早早地帮助我们解决了该问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了。

在我们平常每天使用浏览器浏览网页,使用微信、QQ等工具来聊天时,所有的底层通信细节都得通过socket来实现。而socket,最开始的含义也就是一个IP地址和端口号,唯一表示了使用TCP的一端。

下面对常用的socket网络基础知识进行介绍。

1. SOCKET编程相关基础

1.1 主机字节序和网络字节序

大端字节序是指一个整数的高位字节存储在内存低地址处,地位字节存储在内存的高地址处。

小端字节序刚好相反。

网络传输为大端模式,多数PC机为小端模式。

主机字节序和网络字节序的转换:

#include <netinet/in.h>

unsigned short int htons()

unsigned long int htonl()

unsigned long int ntohl()

unsigned short int ntohs()

即使在同一机器上的两个进程通信,也要考虑字节序问题(JAVA虚拟机采用大端字节序)。

1.2 socket结构体定义

struct sockaddr_in

{

sa_family_t sin_family; //AF_INET

u_int16_t sin_port; //端口号,网络字节序

struct in_addr sin_addr;

};

struct in_addr

{

u_int32_t s_addr; //网络字节序

};

IP地址转换

#include <arpa/inet.h>

in_addr_t inet_addr(const char *strptr);

int inet_aton(const char *cp, struct in_addr *inp);

int inet_pton(int family, const char *src, void *dst);

char *inet_ntoa(struct in_addr in);

const char *inet_ntop(int family, const void *src, char *dst, size_t len);

注:inet_ntoa该函数内部由一个静态变量存储转化结果,不可重入。

inet_addr,不能处理广播地址255.255.255.255,被废弃的函数。用inet_aton或inet_pton代替。

2. 创建SOCKET

#include <sys/type.h>

#include <sys/socket.h>

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

失败时返回-1。

type取值:

SOCKSTREAM SOCKDGRAM

SOCKRAW SOCKSEQPACKET

protocol取值:

IPPROTOTCP IPPROTOUDP

IPPROTO_SCTP

3. 命名SOCKET

int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);//成功返回0,失败返回-1

4. 监听SOCKET

创建socket之后,还不能马上接受客户端连接,创建一个监听队列来存放待处理的客户连接。

int listen(int sockfd, int backlog);

backlog参数置顶内核监听队列的最大长度,典型值为5.

5. 接收连接

从listen监听队列中取出一个连接。

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

accept只是从队列中取出连接,而不论连接处于何种状态,更不关心网络状况的变化。

6. 发起连接

客户端通过connect发起连接。

int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);

常见errno错误:

ECONNREFUSED,目标端口不存在,连接被拒绝。

ETIMEDOUT,连接超时

7. 关闭连接

int close(int fd);

int shutdown(int sockfd, int howto);

close() 系统调用并非总是立即关闭一个连接,而是讲fd引用计数减1,当引用计数为0时,才真正关闭连接。

立即终止连接,应使用shutdown()。

8. 数据读写

8.1 TCP数据读写

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

recv成功时返回实际读取到的数据长度,可能小于期望的长度,因此可能要多次recv,才可读取到完整数据。

8.2 UDP数据读写

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dst_addr, socklen_t addrlen);

9. 举个栗子

一个简单的TCP通信实例如下所示(还是直接截屏吧,不支持代码高亮,markdown确实是硬伤):

server端:

Linux网络编程之基础API使用

socket_server.c

client端:

Linux网络编程之基础API使用

socket_client.c

声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
  • 上一篇:没有了
  • 下一篇:没有了