POSIX Socket编程.docx
- 文档编号:8964699
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:8
- 大小:17.70KB
POSIX Socket编程.docx
《POSIX Socket编程.docx》由会员分享,可在线阅读,更多相关《POSIX Socket编程.docx(8页珍藏版)》请在冰豆网上搜索。
POSIXSocket编程
POSIXSocket编程
一、套接字数据结构1、通用套接字地址structsockaddr
{sa_family_tsa_family;//通信类型,对于IPV4为AF_INET
charsa_data[14];//用来保存IP地址和端口信息,一般不用}2、IPV4套接字地址structsockaddr_in
{unsignedshortsin_len;//IPV4地址长度
sa_family_tsin_family;//通信类型unsignedshortintsin_port;//端口号
structin_addrsin_addr;//IP地址unsignedcharsin_zero[8];//补充字段
}其中structin_addr为:
structin_addr{
uint32_ts_addr;//32位IP地址,网络字节顺序
}
3、hostentstructhostent
{char*h_name;//主机的正式名
char**h_aliases;//主机的别名inth_addrtype;//主机的地址类型,IPV4为AF_INET
inth_length;//地址长度,IPV4为32char**h_addr_list;//主机的IP地址列表
}#defineh_addrh_addr_list[0]//主机的第一个IP地址
POSIX中的数据类型数据类型说明头文件
int8_t带符号的8位整数<sys/types.h>uint8_t无符号的8位整数<sys/types.h>
int16_t带符号的16位整数<sys/types.h>uint16_t无符号的16位整数<sys/types.h>
int32_t带符号的32位整数<sys/types.h>uint32_t无符号的32位整数<sys/types.h>sa_family_t套接字地址结构的地址族<sys/socket.h>socklen_t套接字地址结构的长度,一般为uint32_t<sys/socket.h>
int_port_tTCP或者UDP端口号,一般为uint16_t<netinet/in.h>in_addr_tIPV4地址,一般为uint32_t<netinet/in.h>二、基础函数
1、主机字节序和网络字节序#include<netinet/in.h>
uint32_thtonl(uint32_thostlong)uint16_thtons(uint16_thostsho以上rt)
以上两个函数返回网络字节序uint32_tntohl(uint32_tnetlong)
uint16_tntohs(uint16_tnetshort)以上两个函数返回主机字节序2、字节操作函数#include<string.h>
voidmemset(void*dest,intc,size_tlen)voidmemcpy(void*dest,constvoid*src,size_tnbytes)
intmemcmp(constvoid*ptr1,constvoid*ptr2,size_tnbytes)
3、整数与IP地址转换TCP/IP中的IP地址是以''.''隔开的十进制的数,而套接字中用的是32位的网络字节序的二进制数值。
#include<arpa/inet.h>intinet_aton(constchar*straddr,structin_addr*addrptr)
若成功则返回1,否则返回0参数:
straddr为点分十进制字符串,结果保存在addrptr所指的内存中
char*inet_ntoa(structin_addrinaddr)若成功则返回点分十进制数串的指针,否则返回NULL
参数:
inaddr为32位网络字节的整数,返回点分十进制数串的指针
in_addr_tinet_addr(constchar*straddr)若成功则返回32位的二进制网络字节序的地址,否则返回INADDR_NONE(表示一个不存在的IP地址,其实就是255.255.255.255,就是-1)
参数:
straddr为点分十进制字符串,返回为32位的二进制网络字节序的地址
4、域名与IP地址的转换#include<netdb.h>
structhostent*gethostbyname(constchar*hostname)structhostent*gethostbyaddr(constchar*addr,size_tlen,intfamily)
若成功返回hostent结构指针,否则返回空指针,同时设置h_errno,可以调用hstrerror()函数获取h_errno的值
h_errno的取值:
HOST_NOT_FOUND找不到主机
TRY_AGAIN出错重试NO_RECOVERY不可修复性错误
NO_DATA指定的名字有效,但是没有记录
5、其他常用函数:
若IP地址设为INADDR_ANY则表示本机IP,这时可以在浏览器中输入http:
//localhost:
端口号/
作为客户端向服务器发出链接请求
一般出错信息可以用perror来输出voidperror(constchar*s)
该函数除了会输出字符串s,还会输出错误原因
三、TCP编程
头文件:
#include<sys/socket.h>服务器流程:
socket()→bind()→listen()→accept()→recv()<═>send()→close()客户端流程:
socket()→connect()→send()<═>recv()→close()1、创建套接字
intsocket(intfamily,inttype,intptotocol)若成功则返回套接字描述符,否则返回-1
参数:
family取值:
PF_INET(等价于AF_INET)、PF_INET6(等价于AF_INET6)(PF代表ProtoclFamily协议族,AF代表AddressFamily地址族)
type取值:
SOCK_STREAM、SOCK_DGRAM、SOCK_RAW
ptotocol一般取0
2、绑定端口
intbind(intsockfd,conststructsockaddr*my_addr,socklen_taddrlen)若成功返回0,否则返回-1
若出错,则可以在errno中捕获:
EBADF:
参数sockfd不合法
EACCEDD:
权限不足ENOTSOCK:
参数sockfd是一个文件描述符,而不是socket3、等待监听
intlisten(intsockfd,intbacklog)若成功则返回0,否则返回-1
参数:
sockfd表示要监听的套接字,backlog表示最多同时处理的请求数(若为IPV4则最多为128),若超过这个个数,则客户端会受到ECONNREFUSED错误若出错,则可以在errno中捕获:
EBADF:
参数sockfd不合法EACCEDD:
权限不足EOPNOTSUPP:
指定的socket不支持listen
4、接受链接
intaccept(intsockfd,structsockaddr*addr,socketlen_t*addrlen)若成功则返回新的套接字,否则返回-1
参数:
sockfd表示处于监听的套接字,addr表示客户端的信息accept接受一个链接时会返回一个新的套接字,以后的数据传输就用这个新的套接字处理若出错,则可以用errno捕获:
EBADF:
参数sockfd不合法EFAULT:
参数addr指针指向无法存取的空间
ENOTSOCK:
参数sockfd是一个文件描述符,而不是socketEOPNOTSUPP:
制定的socket不是SOCK_STREAM
EPERM:
防火墙拒绝这个链接ENOBUFS:
系统缓冲内存不足
ENOMEM:
核心内存不足
5、请求链接
intconnect(intsockfd,conststructsockaddr*serv_addr,intaddrlen)若成功返回0,否则返回-1参数:
sockfd表示已经建立好的套接字,serv_addr保存服务器信息若出错,可以在errno中捕获:
EBADF:
参数sockfd不合法EFAULT:
参数addr指针指向无法存取的空间
ENOTSOCK:
参数sockfd是一个文件描述符,而不是socketEISCONN:
参数sockfd的套接字已经处于链接状态
ECONNREFUSED:
链接请求被拒绝ETIMEDOUT:
超时
ENETUNREACH:
无法传送数据包到指定主机EAFNOSUPPORT:
sockaddr结构的sa_family不正确
EALREADY:
socket不能阻断,但是以前的链接操作还未完成
6、数据发送和接收
intsend(intsockfd,constvoid*buf,intlen,unsignedintflags)intrecv(intsockfd,void*buf,intlen,unsignedintflags)
若成功则返回已经发送或者接收的字节数,否则返回-1flags一般置0若出错,可以在errno中捕获:
EBADF:
参数sockfd不合法EFAULT:
参数addr指针指向无法存取的空间
ENOTSOCK:
参数sockfd是一个文件描述符,而不是socketEINTR:
进程被信号中断
EAGAIN:
此动作会中断进程,但参数sockfd的套接字不可中断ENOBUFS:
系统的缓冲内存不足
ENOMEM:
核心内存不足EINVAL:
函数参数不正确7、write和read函数
#include<unistd.h>ssize_twrite(intfd,constvoid*buf,size_tcount)
ssize_tread(intfd,void*buf,size_tcount)若成功返回写入和读取的字节数,否则返回-1注意:
write等价于send,read等价于recv
8、关闭套接字
#include<unistd.h>intclose(intfd)
若成功返回0,否则返回-1
服务器:
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/socket.h>#include<sys/types.h>#include<netinet/in.h>#include<netdb.h>#include<errno.h>#include<unistd.h>#include<arpa/inet.h>
#defineBUFSIZE1024//定义缓冲区的大小
intmain(intargc,char*argv[]){intsockfd,newsockfd;sockaddr_inserver_addr;//服务器的套接字地址sockaddr_inclient_addr;//客户端的套接字地址intport;charbuf[BUFSIZE];//发送缓冲区socklen_taddr_len=sizeof(sockaddr_in);if(argc!
=2)//判断命令行参数{printf("Argumentserror!
Usage:
%sport\n",argv[0]);exit
(1);}
//获取端口号if((port=atoi(argv[1]))<0){printf("Porterror!
Usage:
%sport\n",argv[0]);exit
(1);}
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)//创建服务器Socket{printf("Createsocketerror:
%s\n",strerror(errno));exit
(1);}printf("Createserversocketsuccess!
Socketid:
%d\n",sockfd);
//初始化服务器套接字地址memset(&server_addr,0,sizeof(sockaddr_in));//清零server_addr.sin_family=AF_INET;server_addr.sin_addr.s_addr=htonl(INADDR_ANY);server_addr.sin_port=htons(port);
//绑定if(bind(sockfd,(sockaddr*)(&server_addr),sizeof(sockaddr))==-1){printf("Binderror:
%s\n",strerror(errno));exit
(1);}printf("Bindportsuccess!
localport:
%d\n",port);
//监听if(listen(sockfd,5)==-1){printf("Listenerror:
%s\n",strerror(errno));exit
(1);}printf("Listening...\n");
//服务器阻塞,等待接收连接请求,知道客户端程序发送连接请求while
(1){//接收请求if((newsockfd=accept(sockfd,(sockaddr*)(&client_addr),&addr_len))==-1){printf("Accepterror:
%s\n",strerror(errno));exit
(1);}//打印客户端IPprintf("Servergetconnectionfrom%s\n",inet_ntoa(client_addr.sin_addr));//提示用户输入要发送的数据printf("Connectedsuccessful,pleaseinputthemesage[<1024bytes]:
\n");
//数据存放在buf缓冲区,若正确则返回地址等于缓冲区地址if(fgets(buf,sizeof(buf),stdin)!
=buf){printf("fgetserror!
\n");exit
(1);}
//调用write发送数据,等价于send(newsockfd,buf,strlen(buf),0)//用strlen不用sizeof的原因是只发送用户输入的字符串if(write(newsockfd,buf,strlen(buf))==-1){printf("Writeerror:
%s\n",strerror(errno));exit
(1);}
close(sockfd);
return0;}}客户端:
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/socket.h>#include<sys/types.h>#include<netinet/in.h>#include<netdb.h>#include<errno.h>#include<unistd.h>
#defineBUFSIZE1024
intmain(intargc,char*argv[]){intsockfd;charbuffer[BUFSIZE];sockaddr_inserver_addr;hostent*hostname;intport,nbytes;
if(argc!
=3){printf("Argumentserror!
Usage:
%shostnameprot\n",argv[0]);exit
(1);}
//获得主机名if((hostname=gethostbyname(argv[1]))==NULL){printf("Gethostnameerror\n");exit
(1);}
//获得端口号if((port=atoi(argv[2]))<0){printf("Usage:
%shostnameport\n",argv[0]);exit
(1);}
//建立socketif((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){printf("Createsocketerror:
%s\n",strerror(errno));exit
(1);}printf("Createclientsocketsuccess!
Socketid:
%d\n",sockfd);
memset(&server_addr,0,sizeof(server_addr));server_addr.sin_family=AF_INET;server_addr.sin_port=htons(port);server_addr.sin_addr=*((in_addr*)hostname->h_addr);
//发起连接请求if(connect(sockfd,(sockaddr*)(&server_addr),sizeof(sockaddr))==-1){printf("Connecterror:
%s\n",strerror(errno));exit
(1);}
//连接成功printf("Connectsuccess!
\n");if((nbytes=read(sockfd,buffer,BUFSIZE))==-1){printf("Readerror:
%s\n",strerror(errno));exit
(1);}buffer[nbytes]='\0';printf("Ihavereceived:
%s\n",buffer);
close(sockfd);
return0;}
执行:
./server端口号./clientlocalhost端口号
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- POSIX Socket编程 Socket 编程