第一天 网络socket

//服务端程序
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    //创建socket
    //int socket(int domain, int type, int protocol);
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd<0)
    {
        perror("socket error");
        return -1;
    }
    
    //int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    //绑定
    struct sockaddr_in serv;
    bzero(&serv, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(8888);
    serv.sin_addr.s_addr = htonl(INADDR_ANY); //表示使用本地任意可用IP
    int ret = bind(lfd, (struct sockaddr *)&serv, sizeof(serv));
    if(ret<0)
    {
        perror("bind error");    
        return -1;
    }

    //监听
    //int listen(int sockfd, int backlog);
    listen(lfd, 128);

    //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    struct sockaddr_in client;
    socklen_t len = sizeof(client);
    int cfd = accept(lfd, (struct sockaddr *)&client, &len);  //len是一个输入输出参数
    //const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
    
    //获取client端的IP和端口
    char sIP[16];
    memset(sIP, 0x00, sizeof(sIP));
    printf("client-->IP:[%s],PORT:[%d]\n", inet_ntop(AF_INET, &client.sin_addr.s_addr, sIP, sizeof(sIP)), ntohs(client.sin_port));
    printf("lfd==[%d], cfd==[%d]\n", lfd, cfd);

    int i = 0;
    int n = 0;
    char buf[1024];

    while(1)
    {
        //读数据
        memset(buf, 0x00, sizeof(buf));
        n = read(cfd, buf, sizeof(buf));
        if(n<=0)
        {
            printf("read error or client close, n==[%d]\n", n);
            break;
        }
        printf("n==[%d], buf==[%s]\n", n, buf);    

        for(i=0; i
//客户端代码
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    //创建socket---用于和服务端进行通信
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    if(cfd<0)
    {
        perror("socket error");
        return -1;
    }

    //连接服务端
    //int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    struct sockaddr_in serv;
    serv.sin_family = AF_INET;
    serv.sin_port = htons(8888);
    inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
    printf("[%x]\n", serv.sin_addr.s_addr);
    int ret = connect(cfd, (struct sockaddr *)&serv, sizeof(serv));
    if(ret<0)
    {
        perror("connect error");
        return -1;
    }    

    int n = 0;
    char buf[256];
    while(1)
    {
        //读标准输入数据
        memset(buf, 0x00, sizeof(buf));
        n = read(STDIN_FILENO, buf, sizeof(buf));
        
        //发送数据
        write(cfd, buf, n);

        //读服务端发来的数据
        memset(buf, 0x00, sizeof(buf));
        n = read(cfd, buf, sizeof(buf));
        if(n<=0)
        {
            printf("read error or server closed, n==[%d]\n", n);
            break;
        }
        printf("n==[%d], buf==[%s]\n", n, buf);
    }

    //关闭套接字cfd
    close(cfd);

    return 0;
}

2.2 socket编程主要的API函数介绍

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

函数描述: 创建socket

参数说明:

domain: 协议版本

AF_INET IPV4

AF_INET6 IPV6

AF_UNIX AF_LOCAL本地套接字使用

type:协议类型

SOCK_STREAM 流式, 默认使用的协议是TCP协议

SOCK_DGRAM 报式, 默认使用的是UDP协议

protocal:

一般填0, 表示使用对应类型的默认协议.

返回值:

成功: 返回一个大于0的文件描述符

失败: 返回-1, 并设置errno

当调用socket函数以后, 返回一个文件描述符, 内核会提供与该文件描述符相对应的读和写缓冲区, 同时还有两个队列, 分别是请求连接队列和已连接队列.

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

函数描述: 将socket文件描述符和IP,PORT绑定

参数说明:

socket: 调用socket函数返回的文件描述符

addr: 本地服务器的IP地址和PORT,

struct sockaddr_in serv;

serv.sin_family = AF_INET;

serv.sin_port = htons(8888);

//serv.sin_addr.s_addr = htonl(INADDR_ANY);

//INADDR_ANY: 表示使用本机任意有效的可用IP

inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);

addrlen: addr变量的占用的内存大小

返回值:

成功: 返回0

失败: 返回-1, 并设置errno

int listen(int sockfd, int backlog);

函数描述: 将套接字由主动态变为被动态

参数说明:

sockfd: 调用socket函数返回的文件描述符

backlog: 同时请求连接的最大个数(还未建立连接)

返回值:

成功: 返回0

失败: 返回-1, 并设置errno

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

函数说明:获得一个连接, 若当前没有连接则会阻塞等待.

函数参数:

sockfd: 调用socket函数返回的文件描述符

addr: 传出参数, 保存客户端的地址信息

addrlen: 传入传出参数, addr变量所占内存空间大小

返回值:

成功: 返回一个新的文件描述符,用于和客户端通信

失败: 返回-1, 并设置errno值.

accept函数是一个阻塞函数, 若没有新的连接请求, 则一直阻塞.

从已连接队列中获取一个新的连接, 并获得一个新的文件描述符, 该文件描述符用于和客户端通信. (内核会负责将请求队列中的连接拿到已连接队列中)

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数说明: 连接服务器

函数参数:

sockfd: 调用socket函数返回的文件描述符

addr: 服务端的地址信息

addrlen: addr变量的内存大小

返回值:

成功: 返回0

失败: 返回-1, 并设置errno值

接下来就可以使用write和read函数进行读写操作了.

除了使用read/write函数以外, 还可以使用recv和send函数

读取数据和发送数据:

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

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

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

对应recv和send这两个函数flags直接填0就可以了.

注意: 如果写缓冲区已满, write也会阻塞, read读操作的时候, 若读缓冲区没有数据会引起阻塞.

你可能感兴趣的:(Linux,c++)