当client和server端建立好链接后,就可以调用网络IO进行读写操作了,网络IO操作主要有下面几组:
(1)read()和write();
(2)recv()和send();
(3)recvfrom()和sendto();
(4)readv()和writev();
(5)recvmsg()和sendmsg();
typedef unsigned short sa_family_t;
typedef uint16_t in_port_t;
struct in_addr {
unsigned long s_addr;
}
struct sockaddr {
unsigned short sa_family;
char sa_data[14];
};
sa_family是通信类型,最常用的值是 AF_INET;
sa_data14字节,包含套接字中的目标地址和端口信息;
备注:sockaddr的缺陷:sa_data把目标地址和端口信息混在一起了。
struct sockaddr_in
{
short int sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
备注:字符数组sin_zero[8]的存在是为了保证结构体struct sockaddr_in的大小和结构体struct sockaddr的大小相等,sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)=8;
备注:sockaddr_in结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中。
实例:
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(80);
struct iovec {
void *iov_base; /* Starting address */
size_t iov_len; /* Number of bytes to transfer */
};
struct msghdr {
void *msg_name; //TCP模式下为NULL
socklen_t msg_namelen; //TCP模式下为0
struct iovec *msg_iov; //缓冲区数组
int msg_iovlen;
void *msg_control; //辅助数据
socklen_t msg_controllen;
int msg_flags;
};
(1)msg_name和msg_namelen这两个成员用于套接字未连接的场合(譬如未连接的UDP套接字),它们类似recvfrom和sendto的第五个和第六个参数。msg_name指向一个套接字地址结构,用户存放接收者(对于sendmsg)或发送者(对于recvmsg)的协议地址。如果无需指明协议地址(例如TCP套接字或已连接UDP套接字),msg_name应置为空指针,msg_namelen对于sendmsg是一个值参数,对于recvmsg却是一个值-结果参数。
(2)msg_iov和msg_iovlen这两个成员指定输入或输出缓冲区数组(即iovec结构数组),类似readv或writev的第二个和第三个参数。
(3)msg_control和msg_controllen这两个成员指定可选的辅助数据的位置和大小,msg_controllen对于recvmsg是一个值-结果参数;
备注:对于recvmsg和sendmsg,我们必须区别它们的两个标志变量,一个是传递值flags参数,另一个是所传递msghdr结构的msg_flags成员,它传递的是引用,因为传递给函数的是该结构的地址。只有recvmsg使用msg_flags成员,recvmsg被调用时,flags参数被复制到msg_flags成员,并由内核使用其值驱动接收处理过程,内核还根据recvmsg的结果更新msg_flags成员的值。sendmsg则忽略msg_flags成员,因为它直接使用flags参数驱动发送处理过程。这一点意味着如果想在某个sendmsg调用中设置MSG_DONTWAIT标志,那就把flags参数设置为该值,把msg_flags成员设置为该值不起作用。
#include
ssize_t read(int fd,void *buf,size_t nbyte);
函数功能:负责从fd中读取内容,当读成功时,read返回实际所读的字节数,如果返回的值是0表示已经读到文件的结束了,小于0表示出现了错误。
(1)如果错误为EINTR说明读是由中断引起的;
(2)如果是ECONNREST表示网络连接出了问题;
#include
ssize_t write(int fd, const void*buf,size_t nbytes);
函数功能:write函数将buf中的nbytes字节内容写入文件描述符fd,成功时返回写的字节数,失败时返回-1,并设置errno变量。
(1)如果错误为EINTR表示在写的时候出现了中断错误;
(2)如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接);
#include
#include
int recv(int sockfd,void *buf,int len,int flags);
备注:前3个参数和read一样,不同的是flags,如果flags等于0,则用法和read一样;
(1)MSG_DONTROUTE:不查找表;
(2)MSG_OOB:接受或者发送带外数据;
(3)MSG_PEEK:查看数据,并不从系统缓冲区移走数据,下次读取数据还是一样;(SSL中有用到)
(4)MSG_WAITALL:等待所有数据;
#include
#include
int send(int sockfd,void *buf,int len,int flags);
备注:前3个参数和write一样,不同的是flags,如果flags等于0,则用法和write一样;
(1)MSG_DONTROUTE:不查找表;
(2)MSG_OOB:接受或者发送带外数据;
(3)MSG_PEEK:查看数据,并不从系统缓冲区移走数据,下次读取数据还是一样;(SSL中有用到)
(4)MSG_WAITALL:等待所有数据;
#include
#include
int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);
备注:recvfrom一般用于UDP协议中,但是如果在TCP中connect函数调用后也可以用。
备注:当recvfrom返回时,fromlen包含实际存入from中的数据字节数,返回接收到的字节数或当出现错误时返回-1,并置相应的errno。
备注:当你对于数据报socket调用了connect函数时,你也可以利用send和recv进行数据传输,但该socket仍然是数据报socket,并且利用传输层的UDP服务,但在发送或接收数据报时,内核会自动为之加上目地和源地址信息。
#include
#include
int sendto(int sockfd,const void *msg,int len,unsigned int flags,const struct sockaddr *to,int tolen);
备注:sendto一般用于UDP协议中,但是如果在TCP中connect函数调用后也可以用。
备注:Sendto 函数也返回实际发送的数据字节长度或在出现发送错误时返回-1。
#include
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
函数功能:可以从多个不连续的缓冲里读入,即分散读,成功则返回读的字节数,错误返回-1。(一般先填满第一个缓冲区,再填写下一个,返回的是读到的总字节数,如果遇到文件结尾,无数据可读,则返回0)
#include
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
函数功能:可以从多个不连续的缓冲里写出,即集合写,成功则返回写的字节数,错误返回-1。
char *str0 = "hello ";
char *str1 = "world\n";
struct iovec iov[2];
ssize_t nwritten;
iov[0].iov_base = str0;
iov[0].iov_len = strlen(str0);
iov[1].iov_base = str1;
iov[1].iov_len = strlen(str1);
nwritten = writev(STDOUT_FILENO, iov, 2);
#include
#include
ssize_t recvmsg(int sockfd,struct msghdr *msg,int flags);
备注:若成功则返回读入的字节数,若出错则为-1。
#include
#include
ssize_t sendmsg(int sockfd,struct msghdr *msg,int flags);
备注:若成功则返回写出的字节数,若出错则为-1。
Read/write和recv/send:
http://blog.csdn.net/petershina/article/details/7946615
recvfrom和sendto:
http://blog.csdn.net/liangkaiyang/article/details/5931901
sockaddr_in结构体介绍:
http://blog.sina.com.cn/s/blog_6151984a0100etj1.html
readv和writev:
http://blog.chinaunix.net/uid-26822401-id-3158225.html
http://man7.org/linux/man-pages/man2/writev.2.html
recvmsg和sendmsg:
http://man7.org/linux/man-pages/man2/sendmsg.2.html
http://blog.sina.com.cn/s/blog_976bcdc201018su5.html
socket通信:
http://blog.csdn.net/xiaoweige207/article/details/6211577