Socket基础编程

地址结构sockaddr_in

其中包含:IP地址端口号协议族
推荐使用sockaddr_in,而不建议使用sockaddr
sockaddr_insockaddr是等价的,但sockaddr_in字段更清晰

/*

 * Socket address, internet style.

 */

struct sockaddr_in {

    __uint8_t   sin_len;

    sa_family_t sin_family;

    in_port_t   sin_port;

    struct      in_addr sin_addr;

    char        sin_zero[8];

};

 

sockaddr_in字段描述

// 地址家族,通常使用AF_INET代表TCP/CP协议族(AF_INET6代表IPV6)

sockaddr_in.sin_family



// 端口号,必须转化为网络字节序使用htons和ntohs

sockaddr_in.sin_port



// 用于存储ip地址,必须是网络字节序

sockaddr_in.sin_addr



// 为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节

sockaddr_in.sin_zero

 

sockaddr_in字段初始化

struct sockaddr_in servaddr;

bzero(&servaddr, sizeof(servaddr));



servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(8090);



// 若字符串有效则将字符串转换为32位二进制网络字节序的IPV4地址

servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

// 检测转化IP是否出错

if (servaddr.sin_addr.s_addr == INADDR_NONE) {

    perror("ip");

    exit(-1);

}

可以支持IPV6的IP地址转换方式

// inet_pton能够处理ipv4甚至ipv6(需要改动现在代码)

if (inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr) <= 0) {

    perror("pton");

    exit(-1);

} 

网络字节序和IP转换函数

// 将网络字节序转化为主机字节序

__uint16_t ntohs(__uint16_t);

// 将主机字节序转化为网络字节序

__uint16_t htons(__uint16_t);



__uint32_t ntohl(__uint32_t);

__uint32_t htonl(__uint32_t);
// 若字符串有效则将字符串转换为32位二进制网络字节序的IPV4地址,否则为INADDR_NONE // 其反函数inet_ntoa in_addr_t inet_addr(const char* strptr);

网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序采用big-endian排序方式。

序号
英文名
中文名
描述
1
big-endian
大尾顺序
地址的低位存储值的高位
2
little-endian
小尾顺序
地址的低位存储值的低位 

想判断你的设备大小端吗?使用C语言的Union就可以判断!请看这里 

套接字

创建一个套接字,返回一个套接字描述符

int socket(int domain, int type, int protocol);

 

套接字描述符(socket file descriptor)
套接字描述符是一个整数类型的值,每个进程的进程空间里都有一个套接字描述符表,表中存放着套接字描述符和套接字数据结构的对应关系。
因此根据套接字描述符就可以找到其对应的套接字数据结构。
每个进程在自己的进程空间里都有一个套接字描述符表,但是套接字数据结构都是在操作系统的内核缓冲里

接收发送函数

ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);

ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags);



ssize_t write (int fd,const void * buf,size_t count);

ssize_t read(int fd,void * buf ,size_t count);

 

客户端主要函数

int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);

 

服务器端主要函数

int bind( int sockfd , const struct sockaddr * my_addr, socklen_t addrlen);

int listen(int s, int backlog);

int accept(int s, struct sockaddr * addr, int * addrlen);

 

客户端代码

#include <iostream>



#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <arpa/inet.h>

#include <unistd.h>



const int       MAX_LINE    = 512;

const ushort    SERV_PORT   = 7890;

const char*     SERV_IP     = "127.0.0.1";



int main(int argc, const char * argv[])

{

    int socketfd;



    struct sockaddr_in servaddr;

    memset(&servaddr, 0, sizeof(servaddr));



    servaddr.sin_family = AF_INET;

    servaddr.sin_port = htons(SERV_PORT);



    // 若字符串有效则将字符串转换为32位二进制网络字节序的IPV4地址

//    servaddr.sin_addr.s_addr = inet_addr(SERV_IP);

//    if (servaddr.sin_addr.s_addr == INADDR_NONE) {

//        perror("ip");

//        exit(-1);

//    }



    // 支持IPV6的新的转换方式,推荐

    if (inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr) <= 0) {

        perror("pton");

        exit(-1);

    }



    // 创建一个套接字

    if ( (socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {

        perror("socket");

        exit(-1);

    }



    // 连接到主机

    if (connect(socketfd, (sockaddr*)&servaddr, sizeof(servaddr)) < 0) {

        perror("connect");

        exit(-1);

    }



    // 接收数据

    char recvline[MAX_LINE+1];

    long bytelen = 0;

    while ((bytelen = read(socketfd, recvline, MAX_LINE)) > 0) {

        recvline[bytelen] = 0;

        printf("recv --> %s\n", recvline);

    }



    close(socketfd);

    return 0;

}

 

服务器代码

#include <iostream>



#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

#include <arpa/inet.h>

#include <unistd.h>



const ushort SERV_PORT   = 7890;



int main(int argc, const char * argv[])

{

    struct sockaddr_in serveraddr;

    memset(&serveraddr, 0, sizeof(serveraddr));



    serveraddr.sin_family = AF_INET;

    serveraddr.sin_port = htons(SERV_PORT);

    // 系统自动获取本机IP

    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);



    // 创建一个socket

    int serverfd = socket(AF_INET,SOCK_STREAM,0);

    if (serverfd < 0) {

        perror("socket");

        exit(-1);

    }



    // 绑定端口

    int bind_ret = bind(serverfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    if (bind_ret < 0) {

        perror("bind");

        exit(-1);

    }



    // 开始监听

    // #2: backlog:等待连接队列的最大长度

    if (listen(serverfd, 10) < 0) {

        perror("listen");

        exit(-1);

    }



    printf("---------- listening (127.0.0.1:%d) ----------\n", SERV_PORT);



    // 开始轮询监听请求

    bool toggle = true;

    while (toggle) {

        // 客户端信息结构

        int clientfd;

        struct sockaddr_in clientaddr;

        memset(&serveraddr, 0, sizeof(serveraddr));

        socklen_t len = sizeof(clientaddr);



        // 接收请求,建立连接

        if ( (clientfd = accept(serverfd, (struct sockaddr *)&clientaddr, &len)) < 0 ) {

            perror("accept");

            exit(-1);

        }



        // 向客户端发送信息

        const char *message = "hello world";

        write(clientfd, message, strlen(message)+1);



        // 转为点分十进制ip

        const char *client_ip = inet_ntoa(clientaddr.sin_addr);

        const ushort client_port = ntohs(clientaddr.sin_port);

        printf("client(%s:%u) # send -> %s\n", client_ip, client_port, message);



        // 关闭与客户端的连接

        close(clientfd);

    }



    // 关闭服务监听

    close(serverfd);

    return 0;

}

 

你可能感兴趣的:(socket)