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分别是发起连接和接受连接请求:
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网络编程学习笔记之一 -----各种基础知识小结,布布扣,bubuko.com

linux网络编程学习笔记之一 -----各种基础知识小结

上一篇:Linux 内核网络协议栈 ------ TCP拥塞状态机 tcp_fastretrans_alert


下一篇:Hibernate 分页时 Long 无法转化成Integer类型 异常