① 什么是Socket?
Socket是一个通信的端点。一对进程在网络直接通过一对socket通信,每个进程一个。
一个socket由一个IP地址和端口号确定。Socket封装了一些操作,使得网络里两个进程的数据通信比较方便。基于TCP协议和UDP协议的socket用得很多。下图展示了两种方式的通信过程
②建立socket进行通信使用的几个函数
以Linux系统为例,说明一下几个函数
A. socket()函数
int socket(int domain, int type, int protocol);
这个操作类似于打开文件操作,返回socket的socket描述符。
参数:
domain:协议域,又称为协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL、AF_ROUTE。协议族决定了socket的地址类型,通信时采用与其相符的地址,AF_INET用ipv4地址(32位)和16位端口号的组合
type:指定socket类型,常用的有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET,前两个分别对应TCP和UDP类型的socket
protocol:指定协议,常用有IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC,协议和socket的类型要匹配。0会选择type对应的默认类型。
B. bind()函数
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
把一个地址族的特定地址指定给socket,而不是由系统随机分配.
参数:
sockfd:socket描述符,socket()函数返回的int值
addr:一个地址结构体的const指针,指向要绑定给sockfd的地址,结构体的结构和地址协议相符。
如ipv4的地对应的
struct sockaddr_in { sa_family_t sin_family; /*地址族: AF_INET */ in_port_t sin_port; /*网络字节序的端口号 */ struct in_addr sin_addr; /*internet 地址 */ }; /* Internet 地址. */ struct in_addr { uint32_t s_addr; /* 网络字节序的地址 */ };
C. listen()、connect()函数
使用时依次调用socket(),connect(),然后调用listen()来监听socket,客户端调用connect是,服务器就会收到这个请求。
int listen(int sockfd, int backlog);sockfd是要监听的socket的描述符
backlog是这个socket可以排队连接的最大链接个数,也就是这个socket的等待队列的长度。调用listen,socket开始等待客户的链接请求
int connect(int sockfd, const structsockaddr *addr, socklen_t addrlen);sockfd 是客户端socket描述字
addr为服务器的socket地址
addr_len是socket地址的长度。
客户端通过调用connect函数来建立与TCP服务器的连接。调用listen(),socket开始等待客户的链接请求
D. accept()函数
服务器端第四个要调用的函数,服务器收到请求后,用accept接受请求,然后链接就建立了,可以开始读写操作。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd是服务器socket描述字
addr是指针,用于返回客户端地址
addrlen是协议地址的长度。函数的返回值是内核自动生成的一个全新的描述字,代表一个和客户端的TCP链接
E.read(),write()读写操作
相关函数原型如下所示
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); #include <sys/types.h> #include <sys/socket.h> ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr*dest_addr, socklen_t addrlen); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr*src_addr, socklen_t *addrlen); ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); ssize_t recvmsg(int sockfd, struct msghdr*msg, int flags);
E. close()函数
读写完毕后要关闭相应的socket描述字
#include <unistd.h> int close(int fd);
③代码示例
代码源自http://www.embedu.org/column/column179.htm
TCP socket
TCP 服务端
int main(){ int sock_fd,client_fd; /*sock_fd:监听socket;client_fd:数据传输socket */ struct sockaddr_in ser_addr; /* 本机地址信息 */ struct sockaddr_in cli_addr; /* 客户端地址信息 */ char msg[MAX_MSG_SIZE];/* 缓冲区*/ ser_sockfd=socket(AF_INET,SOCK_STREAM,0);/*创建连接的SOCKET */ if(ser_sockfd<0) {/*创建失败 */ fprintf(stderr,"socker Error:%s\n",strerror(errno)); exit(1); } /* 初始化服务器地址*/ addrlen=sizeof(struct sockaddr_in); bzero(&ser_addr,addrlen); ser_addr.sin_family=AF_INET; ser_addr.sin_addr.s_addr=htonl(INADDR_ANY); ser_addr.sin_port=htons(SERVER_PORT); if(bind(ser_sockfd,(struct sockaddr*)&ser_addr,sizeof(struct sockaddr_in))<0){ /*绑定失败 */ fprintf(stderr,"Bind Error:%s\n",strerror(errno)); exit(1); } /*侦听客户端请求*/ if(listen(ser_sockfd,BACKLOG)<0){ fprintf(stderr,"Listen Error:%s\n",strerror(errno)); close(ser_sockfd); exit(1); } while(1){/* 等待接收客户连接请求*/ cli_sockfd=accept(ser_sockfd,(struct sockaddr*) & cli_addr,&addrlen); if(cli_sockfd<=0){ fprintf(stderr,"Accept Error:%s\n",strerror(errno)); }else{/*开始服务*/ recv(cli_addr,msg,MAX_MSG_SIZE,0); /* 接受数据*/ printf("received a connection from %sn", inet_ntoa(cli_addr.sin_addr)); printf("%s\n",msg);/*在屏幕上打印出来 */ strcpy(msg,"hi,I am server!"); send(cli_addr,msg,sizeof(msg),0); /*发送的数据*/ close(cli_addr); } } close(ser_sockfd); return 0; }
int main(){ int cli_sockfd;/*客户端SOCKET */ int addrlen; char seraddr[14]; struct sockaddr_in ser_addr,/* 服务器的地址*/ cli_addr;/* 客户端的地址*/ char msg[MAX_MSG_SIZE];/* 缓冲区*/ GetServerAddr(seraddr); cli_sockfd=socket(AF_INET,SOCK_STREAM,0);/*创建连接的SOCKET */ if(ser_sockfd<0){/*创建失败 */ fprintf(stderr,"socker Error:%s\n",strerror(errno)); exit(1); } /* 初始化客户端地址*/ addrlen=sizeof(struct sockaddr_in); bzero(&ser_addr,addrlen); cli_addr.sin_family=AF_INET; cli_addr.sin_addr.s_addr=htonl(INADDR_ANY); cli_addr.sin_port=0; if(bind(cli_sockfd,(struct sockaddr*)&cli_addr,addrlen)<0){ /*绑定失败 */ fprintf(stderr,"Bind Error:%s\n",strerror(errno)); exit(1); } /* 初始化服务器地址*/ addrlen=sizeof(struct sockaddr_in); bzero(&ser_addr,addrlen); ser_addr.sin_family=AF_INET; ser_addr.sin_addr.s_addr=inet_addr(seraddr); ser_addr.sin_port=htons(SERVER_PORT); if(connect(cli_sockfd,(struct sockaddr*)&ser_addr,&addrlen)!=0)/*请求连接*/ { /*连接失败 */ fprintf(stderr,"Connect Error:%s\n",strerror(errno)); close(cli_sockfd); exit(1); } strcpy(msg,"hi,I am client!"); send(sockfd,msg,sizeof(msg),0);/*发送数据*/ recv(sockfd,msg,MAX_MSG_SIZE,0); /* 接受数据*/ printf("%s\n",msg);/*在屏幕上打印出来 */ close(cli_sockfd); return 0; }
UDP服务端
int main(){ int ser_sockfd; int len; //int addrlen; socklen_t addrlen; char seraddr[100]; struct sockaddr_in ser_addr; /*建立socket*/ ser_sockfd=socket(AF_INET,SOCK_DGRAM,0); if(ser_sockfd<0){ printf("I cannot socket success\n"); return 1; } /*填写sockaddr_in 结构*/ addrlen=sizeof(struct sockaddr_in); bzero(&ser_addr,addrlen); ser_addr.sin_family=AF_INET; ser_addr.sin_addr.s_addr=htonl(INADDR_ANY); ser_addr.sin_port=htons(SERVER_PORT); /*绑定客户端*/ if(bind(ser_sockfd,(struct sockaddr *)&ser_addr,addrlen)<0){ printf("connect"); return 1; } while(1){ bzero(seraddr,sizeof(seraddr)); len=recvfrom(ser_sockfd,seraddr,sizeof(seraddr),0,(struct sockaddr*)&ser_addr,&addrlen); /*显示client端的网络地址*/ printf("receive from %s\n",inet_ntoa(ser_addr.sin_addr)); /*显示客户端发来的字串*/ printf("recevce:%s",seraddr); /*将字串返回给client端*/ sendto(ser_sockfd,seraddr,len,0,(struct sockaddr*)&ser_addr,addrlen); } return 0; }
int GetServerAddr(char * addrname){ printf("please input server addr:"); scanf("%s",addrname); return 1; } int main(int argc,char **argv){ int cli_sockfd; int len; socklen_t addrlen; char seraddr[14]; struct sockaddr_in cli_addr; char buffer[256]; GetServerAddr(seraddr); /* 建立socket*/ cli_sockfd=socket(AF_INET,SOCK_DGRAM,0); if(cli_sockfd<0){ printf("I cannot socket success\n"); return 1; } /* 填写sockaddr_in*/ addrlen=sizeof(struct sockaddr_in); bzero(&cli_addr,addrlen); cli_addr.sin_family=AF_INET; cli_addr.sin_addr.s_addr=inet_addr(seraddr); //cli_addr.sin_addr.s_addr=htonl(INADDR_ANY); cli_addr.sin_port=htons(SERVER_PORT); bzero(buffer,sizeof(buffer)); /* 从标准输入设备取得字符串*/ len=read(STDIN_FILENO,buffer,sizeof(buffer)); /* 将字符串传送给server端*/ sendto(cli_sockfd,buffer,len,0,(struct sockaddr*)&cli_addr,addrlen); /* 接收server端返回的字符串*/ len=recvfrom(cli_sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&cli_addr,&addrlen); //printf("receive from %s\n",inet_ntoa(cli_addr.sin_addr)); printf("receive: %s",buffer); close(cli_sockfd); return 0; }
说明:
本文由giantpoplar发表于CSDN文章地址 http://blog.csdn.net/giantpoplar/article/details/47657303
转载请保留本说明
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/giantpoplar/article/details/47657303