linux网络编程学习笔记之一

以前小有接触,正好这学期选了一门类似的课,重新整理下。

首先是几个常用的网络基本配置文件:

/etc/hosts       主机名解析/etc/services 不同服务所使用的端口定义/etc/netmasks    网络掩码

然后是地址结构netinet/in.h

每个协议族都定义自己的套接口地址结构,这些结构名字以sockaddr_开头,并以每个协议族对应的唯一后缀结束。地址结构中的某些成员按照网络字节序进行维护。由于历史原因,sockaddr_in中的in_addr是一个结构体,只有一个unsigned long成员s_addr存储其对应形式的IPv4地址,典型赋值:

in_addr addr;addr.s_addr = 0x0100007f;  //127.0.0.1的32位长整形网络字节序addr.s_addr = inet_addr("127.0.0.1"); //更通常的做法

字节序:

注意网络传送使用的大端字节序,发送时总是从低字节开始。

而对于ASCII编码的字符串,首字符总是在内存的低字节。而utf的编码就与大小端有关了。

值-结果参数

把套接口地址结构传递给套接口函数总是通过指针的方式来传递。结构的长度也作为参数来传递,但其传递的方式取决于结构的传递方向:

1. 从进程到内核传递套接口地址,三个典型函数:bind,connect,sendto。其长度参数为整型,确切告知从进程到内核要拷贝多少数据。

2.从内核到进程传递套接口地址,四个典型函数:accept,recvfrom,getsockname,getpeername。它们传递的是指向表示结构大小的整数的指针。

各基本函数:

socket: 创建一个套接字,并为套接字数据结构分配存储空间。protocol字段为0时,系统自动根据协议族和通信类型为其选择相应值。

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

bind:绑定套接字到端口,套接字地址里IP地址字段指定为INADDR_ANY时(在netinet/in.h中定义),内核自动分配本机IP

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

listen:为申请进入的连接建立输入数据队列,将到达本地的客户服务请求保存在此队列上(包括已完成和未完成两个队列),直到程序处理它们。listen函数只用于TCP服务器。backlog的上限由<sys/socket.h>中SOMAXCONN指定。

int listen(int sockfd, int backlog);

connect和accept分别是发起连接和接受连接请求:

accept从已完成队列的队头摘取新套接字

int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);int connect(int sockfd, const struct sockaddr *addr, socklen_t len);

tcp流方式的发送和接收函数:

ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);//flags: 传输标志位,为0时是常规操作,如同write()函数ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);//flags: 传输标志位,为0时是常规操作,如同read()函数,当对方关闭连接时,返回的接收数据长度为0,通常以此判断对方是否关闭。

udp包方式的发送和接收函数:

ssize_t sendto(int s, void *msg, size_t len, int flags, const struct sockaddr *to, int tolen);ssize_t recvfrom(int s, void *buf, size_t, int flag, struct sockaddr *from, int *fromlen);

flag和tcp方式类似

以上函数均是不成功返回-1,并将errno置为相应的错误号。

errno – number of last error。errno 记录系统的最后一次错误代码。代码是一个int型的值,在errno.h中定义。可以通过:

#include<string.h>char *strerror(int errnum);

该函数把错误码,转化成可理解的字符串。

也可直接使用下面这个函数输出出错信息:

void perror ( const char * str );

关闭套接字close, <unistd.h>

在<string.h>中,定义和名字以str开头的函数处理的是以空字符结束的C字符串。有一组以mem开头的内存操作函数在网络编程里比较常用:

void *memset(void *dest, int c, size_t len);

void *memcpy(void *dest, const void *src, size_t nbytes);int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);

字节序转换函数:

#include<netinet/in.h>u_long htonl(u_long hostlong);  u_long ntohl(u_long netlong);  u_short ntohs(u_short netshort);  u_short htons(u_short hostshort);

IP地址转换函数:(a:ascii通常指点分十进制形式,n:network或numeric指整数形式)

#include<arpa/inet.h>int inet_aton(const char*strptr, struct in_addr *addrptr);char *inet_ntoa(struct in_addr inaddr);in_addr_t inet_addr(const char *strptr);//把点分十进制的形式转化为网络中传输的32整形数据,如192.168.1.3 -> 50440384(3*256^3+1*256^2+168*256+192)

注意:255.255.255.255(有限广播地址)不能用inet_addr处理,因为处理后是32个1,与该函数出错时返回的常值INADDR_NONE相同。

套接字地址信息函数:

int getsockname(int s, struct sockaddr *name, socklen_t *namelen);int getpeername(int s, struct sockaddr *name, socklen_t *namelen);

通常我们知道本地和远程的套接字地址信息,不必专门调用函数来获得,但是以下情况例外:

1、TCP客户不调用bind而直接调用connect,此时,应调用getsockname才能获得由系统自动分配给该连接的IP地址和端口号

2、调用bind,且端口参数设为0(让内核选择相应的端口),则调用getsockname获得本地端口

3、TCP服务器调用bind函数,且IP地址参数为INADDR_ANY,则调用getsockname获得由内核分配的本地IP地址

4、在子进程中,由于调用accept进程通过执行exec函数而丢失了原内存的数据,则调用getpeername函数获得远程的套接字地址信息

阳光总在风雨后。只有坚强的忍耐顽强的奋斗,

linux网络编程学习笔记之一

相关文章:

你感兴趣的文章:

标签云: