① 什么是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