Linux网络编程之TCPWord文档下载推荐.docx
《Linux网络编程之TCPWord文档下载推荐.docx》由会员分享,可在线阅读,更多相关《Linux网络编程之TCPWord文档下载推荐.docx(24页珍藏版)》请在冰豆网上搜索。

u32s_addr;
//32位地址
};
(2)相关函数
#include<
sys/socket.h>
sys/types.h>
intsocket(intdomain,inttype,intprotocol);
参数:
domain-通信的域,AF_INET表示IPV4协议,PF_INET6表示IPV6协议
type-设置套接字通信的类型SOCK_STREAM流式套接字,SOCK_DGRAM数据报套接字,SOCK_RAW原始套接字
protocol-表示某个通信类型的特定类型,如果type只有一个类型,那么这个参数设置为0
返回值:
成功返回套接字描述符,失败返回-1
#include<
intbind(intsockfd,conststructsockaddr*my_addr,socket_taddrlen);
sockfd-套接字描述符
my_addr-sockaddr指针类型,指向一个套接字的地址结构
addrlen-地址结构的长度
成功绑定返回0,失败绑定返回-1
intlisten(intsockfd,intbacklog);
backlog-等待队列的长度
成功返回0,失败返回-1
intaccept(intsockfd,structsockaddr*addr,socklen_t*addrlen);
addr-指向地址结构的指针
addrlen-地址结构的长度指针
其中addr包含的是客户端的地址结构,包括客户端的IP,端口号,协议族等等.
成功返回的是用于服务器与客户端通信的套接字描述符,失败返回-1
intconnect(intsockfd,structsockaddr*addr,intaddrlen);
sockfd-客户端套接字描述符
addr-需要连接的服务器的地址结构
addrlen-服务器的地址结构的长度
连接成功返回0,失败返回-1
close(ints);
s-套接字描述符
成功关闭套接字返回0,失败返回-1
3.TCP通信的实例
服务器端:
stdio.h>
stdlib.h>
strings.h>
unistd.h>
linux/in.h>
#definePORT8888
#defineBACKLOG2
//服务器端程序
/**
(1)建立一个套接字描述符,定义网络类型,协议类型和具体的协议标号socket()
(2)将套接字与具体的地址结构绑定,这个地址结构包括端口号,IP地址,网络类型bind()
(3)侦听客户端发出的请求,设置队列的长度listen()
(4)在客户端发出请求后,处理客户端的连接,返回一个新的套接字描述符用于服务器端与客户端的通信accept()
(5)读写数据read()vs.write()
(6)当服务器处理完数据要结构通信过程,关闭连接close()
**/
voidprocess(intsc);
intmain(intargc,char*argv[]){
intss,sc;
//ss为服务器端的套接字描述符,sc为客户端的套接字描述符,即返回的新的套接字描述符
structsockaddr_inserver_addr;
//服务器端的地址结构
structsockaddr_inclient_addr;
//客户端的地址结构
interr;
//返回值
pid_tpid;
//进程的pid
//建立一个流式套接字
ss=socket(AF_INET,SOCK_STREAM,0);
//第一个参数用来设置通信的域,AF_INET表示使用IPv4Internet协议,第二个参数是套接字通信的类型,表示流式套接字,第三个参数表示某种协议的特定类型,如果只有一种类型,设置为0
if(ss<
0){
printf("
socketerror\n"
);
return-1;
//设置服务器的地址结构
bzero(&
server_addr,sizeof(server_addr));
//清0
server_addr.sin_family=AF_INET;
//通信的域,通常与socket函数的domain一致
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
//本地地址
server_addr.sin_port=htons(PORT);
//服务器端口
//绑定地址结构到套接字描述符
err=bind(ss,(structsockaddr*)&
//第一个参数是套接字描述符,第二个参数是sockaddr指针,第三个参数是server_addr的长度
if(err<
0){
perror("
binderror"
//设置侦听
err=listen(ss,BACKLOG);
//第一个参数是服务器端的套接字描述符,第二个参数是侦听队列的长度
listenerror"
for(;
;
){
intaddrlen=sizeof(structsockaddr);
//接收客户端的连接
sc=accept(ss,(structsockaddr*)&
client_addr,&
addrlen);
//第一个参数是服务器端的套接字描述符,第二个参数是sockaddr结构体指针,第三个参数是sockaddr长度的指针
if(sc<
continue;
//客户端的信息存储在sockaddr结构体
intsin_port=client_addr.sin_port;
//返回连接的客户端端口号
portis%d\n"
sin_port);
//建立一个子进程来处理连接
pid=fork();
if(pid==0){//子进程
close(ss);
//关闭服务器的侦听
process(sc);
//处理连接,用返回的新的客户端描述符来处理连接
}else{
close(sc);
//在父进程关闭客户端的连接
voidprocess(intsc){
ssize_tsize=0;
charbuffer[1024];
for(;
size=read(sc,buffer,1024);
//返回读取的字节数
if(size==0)
return;
write(1,buffer,size);
//终端输出
sprintf(buffer,"
%dbytes\n"
size);
write(sc,buffer,strlen(buffer)+1);
//发送给客户端
}
客户端:
(1)建立套接字描述符
(2)connect与服务器端三次握手,连接服务器端
(3)readvswrite
(4)关闭连接
voidprocess(ints);
ints;
//服务器端的地址结构
s=socket(AF_INET,SOCK_STREAM,0);
//建立一个套接字描述符,参数1表示通信的域IPv4协议,参数2表示通信类型流式套接字,参数3表示某种协议的特定类型如果只有一种类型为0
if(s<
//设置服务器地址
//本地地址,可接受任意IP
inet_pton(AF_INET,argv[1],&
server_addr.sin_addr);
//用户输入IP地址
connect(s,(structsockaddr*)&
server_addr,sizeof(structsockaddr));
//连接服务器端第一个参数是客户端套接字描述符,第二个参数是sockaddr指针,第三个参数是sockaddr的长度
process(s);
//客户端接收到数据处理
close(s);
//客户端关闭连接
voidprocess(ints){
ssize_tsize=0;
charbuffer[1024];
size=read(0,buffer,1024);
//从标准输入流读取数据
if(size>
write(s,buffer,size);
//发送给客户端
size=read(s,buffer,1024);
//从客户端读取数据
write(1,buffer,size);
//将数据写到标准输出
测试:
[root@localhost~]#./Server
portis62361
hello
[root@localhost~]#./Client127.0.0.1
6bytes
总结:
本文主要介绍了TCP网络数据发送与接收的流程,相关函数的使用,最后给出了一个具体的服务器与客户端通信的例子.
Linux网络编程之TCP(下)-I/O数据复用
1.介绍
网络数据的发送与接收有多种方式,可以直接直接从套接字读取数据或向套接字写入函数,如read/write.也可以通过向量发送与接收数据,如readv/writev.另外还可以通过消息发送与接收数据,如sendmsg/recvmsg.主要的I/O模型有以下几种:
(1)阻塞I/O-通常情况下,当数据没有到来的时候,会阻塞进程一直等待数据,如recv函数,它是最常用的模型.
(2)非阻塞I/O-当没有数据到达时,程序不会阻塞,而是立即返回,并返回一个错误.
(3)I/O复用-阻塞I/O会一直阻塞程序,而I/O复用是等待一定的时间,如果等待的时间到,那么进程就会返回.如select函数会按照一定的时间轮循环.
(4)信号驱动I/O模型-进程首先注册一个信号处理回调函数,然后继续执行,当有数据到来时,通过发送信号告诉进程,然后处理数据,
(5)异步I/O模型-与信号驱动I/O不同的,异步I/O在内核完成数据复制之后才送信号通知进程。
对于网络数据的处理,通常情况下采用阻塞I/O模型和I/O复用模型.
2.相关函数
(1)字节序的转换
字节序分为大端字节序与小端字节序,所谓小端字节序就是低字节部分存放于低地址,高字节部分存放于高地址.大端字节序正好相反.在网络数据传输中,涉及到两个字节序,一个是主机字节序,另一个是网络字节序。
主机字节序可以是小端字节序也可以是大端字节序,而网络字节序是大端字节序。
这样,在发送数据的时候,会进行字节序的相应转换。
arpa/inet.h>
uin32_thtonl(uint32_thostlong);
//主机字节序转换成网络字节序长整形
uin16_thtons(uint16_thostshort);
//主机字节序转换成网络字节序短整形
uint32_tntohl(uint32_tnetlong);
//网络字节序转换成主机字节序长整形
uint16_tntohs(uint16_tnetshort);
//网络字节序转换成主机字节序短整形
(2)IP地址的转换
netinet/inet.h>
in_addr_tinet_addr(constchar*cp);
//将字符串的IP地址转换为in_addr类型
char*inet_ntoa(structin_addrin);
//将in_addr类型的二进制地址转换成字符串
intinet_pton(intaf,constchar*src,void*dst);
//将字符串类型的IP地址转换成in_addr
af-协议族
src-表示需要转换的字符串
dst-指向structin_addr指针
返回0表示转换成功,-1表示协议af不支持。
constchar*inet_ntop(intaf,constvoid*src,char*dst,socklen_tcnt);
//把in_addr类型的二进制地址转换成字符串
参数
src-指针structin_addr的指针
dst-保存转换字符串的缓冲区
cnt-此缓冲区的长度
当发生错误时,返回NULL.成功返回指向dst的指针。
(3)获得主机信息
netdb.h>
structhostent*gethostbyname(constchar*name);
成功返回指向hostent的指针,返回NULL表示发生错误。
错误类型保存在errno中:
HOST_NOT_FOUND:
表示查询的主机不存在
NO_ADDRESS和NO_DATA:
请求的名称合法但没有合适的IP地址
NO_RECOVERY:
域名服务器不响应
TRY_AGAIN:
域名服务器出现临时性错误,请重试。
structhostent{
char*h_name;
//主机的正式名称
char**h_aliases;
//别名列表
inth_addrtype;
//主机地址类型
inth_length;
//地址长度
char**h_addr_list;
//地址列表
#defineh_addrh_addr_list[0]
structhostent*gethostbyaddr(constvoid*addr,intlen,inttype);
//通过地址来查看主机的信息
addr-structin_addr指针,表示主机的IP地址
len-所指地址的长度,即sizeof(structin_addr)
type-表示协议族
成功返回hostent指针,错误返回NULL,同上.
(4)协议名称处理函数
structprotent*getprotobyname(constchar*name);
//通过协议名获得相关的协议项
structprotent*getprotobynumber(intproto);
//通过协议值获得相关协议项
voidsetprotoent(intstayopen);
//设置协议文件的打开状态,打开/etc/protocols文件
structprotoent{
char*p_name;
//协议的官方名称
char**p_aliases;
//协议的别名
intp_proto;
//协议的值
(5)recv与send函数
ssize_trecv(ints,void*buf,size_tlen,intflags);
函数recv表示从套接字s接收数据放到数据缓冲区buf中,
buf-接收缓冲区指针
len-接收缓冲区的长度(缓冲区的size,如1024)
flags-表示接收数据的方式,通常为0
flags:
MSG_DONTWAIT-非阻塞操作,立刻返回
MSG_ERRQUEUE-错误消息从套接字错误队列接收
MSG_OOB-接收带外数据
MSG_PEEK-查看数据,不进行数据缓冲区的清空
MSG_TRUNC-返回所有数据,即使指定缓冲区过小
MSG_WAITALL-等待所有消息
成功返回接收的字节数,错误返回-1.查看errno可获得错误信息.
ssize_tsend(ints,constvoid*buf,size_tlen,intflags);
将缓冲区buf中大小为len的数据发送出去.
s-发送数据的套接字描述符
buf-发送缓冲区指针
len-要发送的数据长度(即使缓冲区大小为1024,只有10个字节数据要发送,那么len=10)
flags-发送数据的方式
成功返回发送数据的字节数,发送错误返回为-1.
(6)readv与writev函数
这两函数可以使用向量缓冲区进行数据的发送与接收,即多个缓冲区.
sys/uio.h>
ssize_treadv(intfd,conststructiovec*vector,intcount);
structivoec{
void*iov_base;
//向量缓冲区的地址
size_tiov_len;
//向量缓冲区的大小
fd-套接字描述符
vector-缓冲区指针
count-vector的个数
structiovec就是一个缓冲区,可以接收count个缓冲区的数据
成功返回表示接收到的字节数,失败返回-1,返回值保存在errno
ssize_twritev(intfd,conststructiovec*vector,count);
vector-向量缓冲区指针
count-缓冲区的个数
成功返回表示发送的字节数,失败返回-1
(6)recvmsg函数与sendmsg函数
ssize_trecvmsg(ints,structmsghdr*msg,intflags);
从套接字s中接收数据放入缓冲区msg中。
msg-structmsghdr结构体指针
flags-接收标志信息同send,recv标志.
structmsghdr{
void*msg_name;
//可选地址
socklen_tmsg_namelen;
//可选地址的长度
structiovec*msg_iov;
//接收数据的缓冲区
size_tmsg_iovlen;
//msg_iov的数量
void*msg_control;
//控制缓冲区,根据msg_flags放入不同的值
socklen_tmsg_controllen;
//控制缓冲区的长度
intmsg_flags;
//接收消息的标志
成功返回接收的字节数,失败返回-1.
ssize_tsendmsg(ints,conststructmsghdr*msg,intflags);
向msg中写入数据并发送.
flags-发送数据的标志
成功返回发送的字节数,失败返回-1.
(7)I/O复用函数
sys/select.h>
sys/time.h>
intselect(intnfds,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,structtimeval*timeout);
select函数对文件描述符进行查询,查看目标是否可以进行读,写或者是错误操作,直到条件满足时才进行真正的I/O操作.
nfds-所有文件描述符最大值加1
readfds-读文件描述符集合,这个文件描述符集合监视任何可读文件,当select返回时,readfds将清除不可读的文件描述符,只留下可