码迷,mamicode.com
首页 > 编程语言 > 详细

Socket通信——Linux下,使用C/C++

时间:2015-08-14 13:51:58      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:socket   c++   

①  什么是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;     /* 网络字节序的地址 */
};

应该注意使用htol,htos函数将主机字节顺序转换为网络字节顺序,避免潜在的错误。

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;
 }

TCP 客户端

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 Socket

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;
}

UDP客户端

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

转载请保留本说明

版权声明:本文为博主原创文章,未经博主允许不得转载。

Socket通信——Linux下,使用C/C++

标签:socket   c++   

原文地址:http://blog.csdn.net/giantpoplar/article/details/47657303

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!