POSIX Socket编程.docx

上传人:b****7 文档编号:8964699 上传时间:2023-02-02 格式:DOCX 页数:8 大小:17.70KB
下载 相关 举报
POSIX Socket编程.docx_第1页
第1页 / 共8页
POSIX Socket编程.docx_第2页
第2页 / 共8页
POSIX Socket编程.docx_第3页
第3页 / 共8页
POSIX Socket编程.docx_第4页
第4页 / 共8页
POSIX Socket编程.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

POSIX Socket编程.docx

《POSIX Socket编程.docx》由会员分享,可在线阅读,更多相关《POSIX Socket编程.docx(8页珍藏版)》请在冰豆网上搜索。

POSIX Socket编程.docx

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端口号

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1