socket

网络API(应用程序编程接口),实现相同或不同主机上的进程通信

头文件:
    #include <sys/types.h>   
    #include <sys/socket.h>
原型:
    int socket(int domain, int type, int protocol);
参数:
    int domain:Linux支持的协议族(地址族);
        AF_UNIX, AF_LOCAL   Local communication              unix(7)
        AF_INET             IPv4 Internet protocols          ip(7)
        AF_INET6            IPv6 Internet protocols          ipv6(7);
    int type:套接字类型
        SOCK_STREAM:字节流式套接字----> TCP
        SOCK_DGRAM: 数据报式套接字----> UDP
        SOCK_RAW:原始套接字,传输协议需要在第三个参数指定;
    int protocol:传输协议。如果不需要填0;
    IPPROTO_TCP 和 IPPROTO_UDP;
返回值:
    成功,返回套接字的文件描述符;
    失败,返回-1,更新errno;  
例程:
    //UDP
    int sfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sfd < 0)
    {
        perror("socket");
        return -1;
    }

bind

服务器:(必须)绑定本地的IP和端口号到套接字

客户端:(非必需)绑定本地的IP和端口号到套接字

头文件:
    #include <sys/types.h>   
    #include <sys/socket.h>
原型:
    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:
    int sockfd:socket创建的套接字;
    struct sockaddr *addr:通用地址结构体,一般不采用该结构体,不同的协议族采用不同的地址结构体(详见socket),调用时强制转换到通用地址结构体;
    socklen_t addrlen:地址结构体的大小,sizeof(struct sockaddr_in);
返回值:
    成功,返回0;
    失败,返回-1,更新errno;
例程:
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(PORT);
    saddr.sin_addr.s_addr = inet_addr(IP);
    if(bind(sfd,(struct sockaddr*)&saddr,sizeof(saddr)) < 0)
    {
        ERR_LOG("bind");
        return -1;
    }

recvfrom

接收发送端的数据,并获取发送端的IP和端口号

头文件:
    #include <sys/types.h>
    #include <sys/socket.h>
原型:
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
参数:
    int sockfd:socket创建的套接字;
    void *buf:存储接收到的数据;
    size_t len:要接收的长度;
    int flags:接收方式,0:阻塞方式接收;
    struct sockaddr *src_addr:通用地址结构体,存储发送端的IP和端口号。如果不想接收,填NULL;
    socklen_t *addrlen:第五个参数地址结构体的大小,注意是指针类型;
返回值:
    >0,返回接收到的字节数;
    ==0; 对方关闭,只能用于TCP;
    -1;错误,更新errno;
例程:
    //服务端
    struct sockaddr_in caddr;
    socklen_t caddr_len = sizeof(caddr); 
    char buf[N] = "";
    res = recvfrom(sfd,buf,N,0,(struct sockaddr*)&caddr,&caddr_len);
    if(res < 0)
    {
        ERR_LOG("recvfrom");
        return -1;
    }
    printf("[%s:%d]:",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
    puts(buf);
    //客户端
    if(recvfrom(sfd, buf, N, 0, NULL, NULL) < 0)
    {
        ERR_LOG("recvfrom");
        return -1;
    }

sendto

发送数据给对方

头文件:
    #include <sys/types.h>
    #include <sys/socket.h>
原型:
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
参数:
    int sockfd:socket创建的套接字;
    void *buf:存储要发送的数据;
    size_t len:指定要发送的数据大小;
    int flags:发送方式,填0,阻塞方式发送。如果没有数据发送,则阻塞在该函数上;
    struct sockaddr *dest_addr:存储着目标的IP和端口,据此来发送;
    socklen_t addrlen:地址结构体的大小;
返回值:
    成功,返回发送成功的字节数;
    失败,返回-1,更新errno;
例程:
    //服务器
    if(sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&caddr,caddr_len) < 0)
    {
        ERR_LOG("sendto");
        return -1;
    }
    //客户端
    if(sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&saddr,sizeof(saddr))<0)
    {
        ERR_LOG("sendto");
        return -1;
    }

UDP模型

UDP服务器

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define ERR_LOG(msg) do{\
    perror(msg);\
    printf("%d %s %s\n",__LINE__,__func__,__FILE__);\
}while(0)
#define IP "192.168.1.141"
#define PORT 8888
#define N 128
int main(int argc, const char *argv[])
{
    //1、创建socket套接字
    int sfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sfd < 0)
    {
        ERR_LOG("socket");
        return -1;
    }
    //2、bind服务器的IP & PORT
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(PORT);
    saddr.sin_addr.s_addr = inet_addr(IP);
    if(bind(sfd,(struct sockaddr*)&saddr,sizeof(saddr)) < 0)
    {
        ERR_LOG("bind");
        return -1;
    }
    struct sockaddr_in caddr;
    socklen_t caddr_len = sizeof(caddr); 
    char buf[N] = "";
    int res;
    while(1)
    {
        //3、recvfrom接收数据
        bzero(buf,sizeof(buf));
        res = recvfrom(sfd,buf,N,0,(struct sockaddr*)&caddr,&caddr_len);
        if(res < 0)
        {
            ERR_LOG("recvfrom");
            return -1;
        }
        printf("[%s:%d]:",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
        puts(buf);
        //4、sendto发送数据
        strcat(buf,"*_*");
        if(sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&caddr,caddr_len) < 0)
        {
            ERR_LOG("sendto");
            return -1;
        }
    }
    //5、close文件描述符
    close(sfd);
    return 0;
}

UDP客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define ERR_LOG(msg) do{\
    perror(msg);\
    printf("%d %s %s\n",__LINE__,__func__,__FILE__);\
}while(0)
#define IP "192.168.1.141"
#define PORT 8888
#define N 128
int main(int argc, const char *argv[])
{
    //1、创建socket套接字
    int sfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sfd < 0)
    {
        ERR_LOG("socket");
        return -1;
    }
    //2、填充服务器ip&port信息
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(PORT);
    saddr.sin_addr.s_addr = inet_addr(IP);
    char buf[N] = "";
    int res;
    while(1)
    {
        //3、recvfrom接收数据
        bzero(buf,sizeof(buf));
        res = recvfrom(sfd,buf,N,0,NULL,NULL);
        if(res < 0)
        {
            ERR_LOG("recvfrom");
            return -1;
        }
        printf("[%s:%d]:",inet_ntoa(saddr.sin_addr),ntohs(saddr.sin_port));
        puts(buf);
        //4、sendto送数据
        strcat(buf,"*_*");
        if(sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&saddr,sizeof(saddr)) < 0)
        {
            ERR_LOG("sendto");
            return -1;
        }
    }
    //5、close文件描述符
    close(sfd);
    return 0;
}
Last modification:2021 年 04 月 20 日 16 : 35 : 45