[原创] Linux 网络编程 总结

1、所用到的头文件:
 

sys/types.h:数据类型定义

sys/socket.h:提供socket函数及数据结构

netinet/in.h:定义数据结构sockaddr_in

arpa/inet.h:提供IP地址转换函数

netdb.h:提供设置及获取域名的函数(DNS相关)

sys/ioctl.h:提供对I/O控制的函数

sys/poll.h:提供socket等待测试机制的函数


其他在网络程序中常见的头文件 
unistd.h:提供通用的文件、目录、程序及进程操作的函数

errno.h:提供错误号errno的定义,用于错误处理

fcntl.h:提供对文件控制的函数(控制 socket 是否 blocking)

time.h:提供有关时间的函数(select 需要用到)

crypt.h:提供使用DES加密算法的加密函数

pwd.h:提供对/etc/passwd文件访问的函数

shadow.h:提供对/etc/shadow文件访问的函数

pthread.h:提供多线程操作的函数

signal.h:提供对信号操作的函数

sys/wait.h、sys/ipc.h、sys/shm.h:提供进程等待、进程间通讯(IPC)及共享内存的函数

 
 
1、网络地址结构体:
 
struct sockaddr
{
    unsigned short sa_family;     // address family, AF_xxx
    char sa_data[14];                  // 14 bytes of protocol address
};
 
struct sockaddr_in
{
    short int sin_family;                 // Address family
    unsigned short int sin_port;     // Port number
    struct in_addr sin_addr;         // Internet address
    unsigned char sin_zero[8];     // Same size as struct sockaddr
};
 
 
2、网络字节序转换函数:
 
htons() – "Host to Network Short"
htonl() – "Host to Network Long"
ntohs() – "Network to Host Short"
ntohl() – "Network to Host Long"
  
 
3、IP地址转换函数:
inet_addr()
ina.sin_addr.s_addr = inet_addr("10.12.110.57");
 
int inet_aton(const char *cp, struct in_addr *inp);
注意:返回0为失败!返回非0为成功!
 
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
inet_aton("10.12.110.57", &(my_addr.sin_addr));
memset(&(my_addr.sin_zero), ’\0’, 8); // zero the rest of the struct
 
 
inet_ntoa()
printf("%s", inet_ntoa(ina.sin_addr));
返回值保存在一个静态变量中,每次调用这个函数,均会刷新返回值。
 
4、socket()–Get the File Descriptor!
int socket(int domain, int type, int protocol);
 
domain: AF_INET
type: SOCK_STREAM, SOCK_DGRAM
protocol: 0
 
返回:socket 文件描述符,或 -1,错误代码在errno。
 
 
5、bind()–What port am I on?
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
参数:
addrlen:sizeof(struct sockaddr)
返回:错误-1,错误代码在errno
 
自动获取IP地址:
my_addr.sin_addr.s_addr = INADDR_ANY
自动获取端口号:
my_addr.sin_port = 0
 
 
 
6、connect()–Hey, you!
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
 
返回:错误-1,错误代码在errno
 
当用来连接的socket没有进行bind时,会自动将此socket bind到一个任意端口上。
 
 
7、listen()–Will somebody please call me?
int listen(int sockfd, int backlog);
参数:
sockfd:如果不进行bind,则操作系统会任意将此socket bind到一个任意端口!
backlog:接入等待队列长度,默认为20
返回:错误-1,错误代码在errno
 
 
8、accept()–"Thank you for calling port 3490."
int accept(int sockfd, void *addr, int *addrlen);
参数:
sockfd:用来listen的socket
addr:用来接收连接方的地址信息
addrlen:设定为 sizeof(struct sockaddr),期望接收的地址信息长度,如果接收少了的话,accept函数会改变此值。
 
返回:一个新的socket 描述符!错误返回-1,错误代码在errno。
 
 
9、send() –Talk to me, baby!
int send(int sockfd, const void *msg, int len, int flags);
参数:
sockfd:socket描述符
msg:要发送的信息
len:发送信息的长度
flags:0
 
返回:实际发送的长度,错误返回-1,错误代码在errno。
 
注意:实际发送的长度有可能小于期望发送的长度!需要循环发送。
 
10、recv()–Talk to me, baby!
int recv(int sockfd, void *buf, int len, unsigned int flags);
参数:
buf:接收缓冲区
len:接收缓冲区长度
 
返回:实际接收的长度,错误返回-1,错误代码在errno。返回0,说明对方关闭了链接。
 
11、sendto() –Talk to me, DGRAM-style
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);
参数:
to:对方的地址和端口。
tolen:sizeof(struct sockaddr)
 
返回:实际发送的长度(有可能小于期望发送的长度!),错误返回-1,错误代码在errno。
 
 
 
12、recvfrom()–Talk to me, DGRAM-style
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
参数:
from:发送方的地址信息。
fromlen:期望接收的发送方的地址信息长度(sizeof(struct sockaddr)),如果实际接收比这个值小,则recvfrom函数会更改这个参数。
 
注意:如果将SOCK_DGRAM类型的socket connect之后,可以使用send(),recv()函数收发数据,函数将自动添加相应的地址信息!但是仍然使用的是UDP协议!
 
 
13、close() and shutdown()–Get outta my face!
close(sockfd); 双向关闭一个socket,不能再进行收发操作。
int shutdown(int sockfd, int how);
参数:
how:0不能继续读,1不能继续写,2不能继续读写
返回:0成功,错误返回-1,错误代码在errno
 
注意:
如果使用shutdown在connect之后的SOCK_DGRAM类型的socket上,则会禁止使用send()和recv()进行数据传输。
shutdown没有真正关闭socket文件标示符,只是改变了可用性。如果需要真正关闭,需要调用close()
 
 
14、getpeername()–Who are you?
int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
得到一个连接后的SOCK_STREAM类型socket对方的地址信息。
 
 
15、gethostname()–Who am I?
int gethostname(char *hostname, size_t size);
返回当前主机的主机名。
 
 
 
16、DNS
struct hostent *gethostbyname(const char *name);
 
数据结构:
struct hostent
{
    char *h_name;
    char **h_aliases;
    int h_addrtype;
    int h_length;
    char **h_addr_list;
};
#define h_addr h_addr_list[0]
 
返回:错误返回NULL,错误代码在h_errno
 
 
17、Blocking
sockfd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
这样处理之后的socket在recv() 或者recvfrom()之后不会block,如果没有数据,会返回-1,errorno会被设定为“EWOULDBLOCK”
注意:这种方式会造成忙等待。
 
18、select()–Synchronous I/O Multiplexing
int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
同时监视多组文件描述符,如果有文件描述符可以被(读、写、出现异常),select返回,并且将对应文件描述符组修改为出现时间的文件描述符。通过检测每个文件描述符组,就可以知道出现事件的文件描述符。
 
参数:
numfds:应该被设定为最大的文件描述符+1(越是后建立的socket,描述符越大)
readfds:用来读取的文件描述符组,当不关心时,设置为NULL
writefds:用来写入的文件描述符组,当不关心时,设置为NULL
exceptfds:出现异常的文件描述符组,当不关心时,设置为NULL
timeout:超时时间,当超过这个时间后,select将直接返回。当设定为NULL时,永不超时。
 
操作fd_set的宏定义:
FD_ZERO(fd_set *set) – clears a file descriptor set
FD_SET(int fd, fd_set *set) – adds fd to the set
FD_CLR(int fd, fd_set *set) – removes fd from the set
FD_ISSET(int fd, fd_set *set) – tests to see if fd is in the set
 
拷贝两个fd_set:a = b
 
时间结构体:
struct timeval
{
    int tv_sec; // seconds
    int tv_usec; // microseconds
};
 
 
19、循环发送
int sendall(int s, char *buf, int *len)
{
    int total = 0; // how many bytes we’ve sent
    int bytesleft = *len; // how many we have left to send
    int n;
    while(total < *len) {
        n = send(s, buf+total, bytesleft, 0);
        if (n == -1) { break; }
        total += n;
        bytesleft -= n;
    }
    *len = total; // return number actually sent here
    return n==-1?-1:0; // return -1 on failure, 0 on success
}
 
 

转载于:https://www.cnblogs.com/icemoon1987/archive/2012/11/28/2793402.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值