Socket编程实践(3) --Socket API

简介: socket函数#include #include int socket(int domain, int type, int protocol);创建一个套接字用于通信参数: ...

socket函数

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

创建一个套接字用于通信

参数:

   domain:指定通信协议族(protocol family),常用取值AF_INET(IPv4)

   type:指定socket类型, 流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW

   protocol:协议类型,常用取值0, 使用默认协议

返回值:

   成功: 返回非负整数,套接字;

   失败: 返回-1


bind函数

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

绑定一个本地地址到套接字

参数:

   sockfd:socket函数返回的套接字

   addr:要绑定的地址

//sockaddr_in结构, bind时需要强制转换成为struct sockaddr*类型
struct sockaddr_in
{
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */
    struct in_addr sin_addr;   /* internet address */
};
/* Internet address. */
struct in_addr
{
    uint32_t       s_addr;     /* address in network byte order */
};
/**示例:INADDR_ANY的使用, 绑定本机任意地址**/
int main()
{
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
        err_exit("socket error");

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8001);
    //绑定本机的任意一个IP地址, 作用同下面两行语句
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    //inet_aton("127.0.0.1", &addr.sin_addr);
    //addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    if (bind(listenfd, (const struct sockaddr *)&addr, sizeof(addr)) == -1)
        err_exit("bind error");
    else
        cout << "bind success" << endl;
}

listen函数

int listen(int sockfd, int backlog);

   listen函数应该用在调用socketbind函数之后, 并且用在调用accept之前用于将一个套接字从一个主动套接字转变成为被动套接字。

backlog说明:

对于给定的监听套接口,内核要维护两个队列:

   1、已由客户发出并到达服务器,服务器正在等待完成相应的TCP三路握手过程(SYN_RCVD状态)

   2、已完成连接的队列(ESTABLISHED状态)

但是两个队列长度之和不能超过backlog


backlog推荐使用SOMAXCONN(3.13.0-44-generic中该值为128), 使用等待队列的最大值;

 

Man-Page中的listen说明:

   listen() marks the socket referred to by sockfd as a passive socket, that is, as a socket that 

will be used to accept incoming connection requests using accept(2).

   The sockfd argument is a file descriptor that refers to a socket of type  SOCK_STREAM  or 

SOCK_SEQPACKET.

   The backlog argument defines the maximum length to which the queue of pending connections for 

sockfd may grow.  If a connection request arrives when the queue is full, the  client may  receive

an  error with an indication of ECONNREFUSED or, if the underlying protocol supports retransmission, 

the request may be ignored so that a later reattempt at  connection succeeds.

  If the backlog argument is greater than the value in  /proc/sys/net/core/somaxconn(Ubuntu 14.04 该值为128),  then it  is  silently truncated to that value; the default value in this file is 128.  In kernels

before 2.4.25, this limit was a hard coded value, SOMAXCONN, with the value 128.

 

accept函数

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

已完成连接队列返回第一个连接(the first connection request on the queue of  pending  connections  for the listening 

socket, sockfd, creates a new connected socket, and returns a new file descriptor referring to that socket. 

The newly created socket  is  not  in  the listening state),如果已完成连接队列为空,则阻塞。The original 

socket sockfd is unaffected by this call.

 

参数:

   sockfd:服务器套接字

   addr:将返回对等方的套接字地址, 不关心的话, 可以设置为NULL

   addrlen:返回对等方的套接字地址长度, 不关心的话可以设置成为NULL, 否则一定要初始化

返回值:

   On  success, these system calls return a non-negative integer that is a descriptor for the accepted 

socket.  On error, -1 is returned, and errno is set appropriately.

 

connect函数

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

建立一个连接至addr所指定的套接字

参数:

   sockfd:未连接套接字

   addr:要连接的套接字地址

   addrlen:第二个参数addr长度

 

示例:echo server/client实现

//server端代码
int main()
{
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
        err_exit("socket error");

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8001);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(listenfd, (const struct sockaddr *)&addr, sizeof(addr)) == -1)
        err_exit("bind error");
    if (listen(listenfd, SOMAXCONN) == -1)
        err_exit("listen error");

    char buf[512];
    int readBytes;
    struct sockaddr_in clientAddr;
    //谨记: 此处一定要初始化
socklen_t addrLen = sizeof(clientAddr);
    while (true)
    {
        int clientfd = accept(listenfd, (struct sockaddr *)&clientAddr, &addrLen);
        if (clientfd == -1)
            err_exit("accept error");
        //打印客户IP地址与端口号
        cout << "Client information: " << inet_ntoa(clientAddr.sin_addr)
             << ", " << ntohs(clientAddr.sin_port) << endl;

        memset(buf, 0, sizeof(buf));
        while ((readBytes = read(clientfd, buf, sizeof(buf))) > 0)
        {
            cout << buf;
            if (write(clientfd, buf, readBytes) == -1)
                err_exit("write socket error");
            memset(buf, 0, sizeof(buf));
        }
        if (readBytes == 0)
        {
            cerr << "client connect closed..." << endl;
            close(clientfd);
        }
        else if (readBytes == -1)
            err_exit("read socket error");
    }
    close(listenfd);
}
//client端代码
int main()
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
        err_exit("socket error");

    //填写服务器端口号与IP地址
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8001);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    if (connect(sockfd, (const struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)
        err_exit("connect error");

    char buf[512];
    while (fgets(buf, sizeof(buf), stdin) != NULL)
    {
        if (write(sockfd, buf, strlen(buf)) == -1)
            err_exit("write socket error");
        memset(buf, 0, sizeof(buf));
        int readBytes = read(sockfd, buf, sizeof(buf));
        if (readBytes == 0)
        {
            cerr << "server connect closed... \nexiting..." << endl;
            break;
        }
        else if (readBytes == -1)
            err_exit("read socket error");
        cout << buf;
        memset(buf, 0, sizeof(buf));
    }
    close(sockfd);
}

附-Makefile

.PHONY: clean all 
CC = g++ 
CPPFLAGS = -Wall -g -pthread -std=c++11
BIN = server client
SOURCES = $(BIN.=.cpp)

all: $(BIN)
$(BIN): $(SOURCES) 

clean:
    -rm -rf $(BIN) bin/ obj/ core


目录
相关文章
|
1月前
|
JavaScript 前端开发 API
深入浅出:Vue 3 Composition API 的魅力与实践
【2月更文挑战第13天】 本文将探索 Vue 3 的核心特性之一——Composition API。通过对比 Options API,本文旨在揭示 Composition API 如何提高代码的组织性和可复用性,并通过实际案例展示其在现代前端开发中的应用。不同于传统的技术文章摘要,我们将通过一个具体的开发场景,引领读者步入 Composition API 的世界,展现它如何优雅地解决复杂组件逻辑的管理问题,从而激发读者探索和运用 Vue 3 新特性的热情。
21 1
|
2月前
|
数据采集 监控 算法
利用大数据和API优化电商决策:商品性能分析实践
在数据驱动的电子商务时代,大数据分析已成为企业提升运营效率、增强市场竞争力的关键工具。通过精确收集和分析商品性能数据,企业能够洞察市场趋势,实现库存优化,提升顾客满意度,并显著增加销售额。本文将探讨如何通过API收集商品数据,并将这些数据转化为对电商平台有价值的洞察。
|
2月前
|
人工智能 NoSQL Serverless
基于函数计算3.0 Stable Diffusion Serverless API 的AI艺术字头像生成应用搭建与实践的报告
本文主要分享了自己基于函数计算3.0 Stable Diffusion Serverless API 的AI艺术字头像生成应用搭建与实践的报告
469 6
基于函数计算3.0 Stable Diffusion Serverless API 的AI艺术字头像生成应用搭建与实践的报告
|
3月前
|
存储 缓存 测试技术
4个所有开发人员都应该知道的关键API缓存实践
4个所有开发人员都应该知道的关键API缓存实践
|
2月前
|
安全 前端开发 API
深入理解与实践GraphQL:构建高效、灵活的API
在本文中,我们将探索GraphQL这一强大的API查询语言及其运行原理。不同于传统的RESTful API设计,GraphQL提供了一种更加高效、灵活的方式来交互数据。通过实例和比较,本文旨在揭示GraphQL如何使前端和后端开发更加紧密协作,同时减少数据传输的冗余。我们将从GraphQL的基本概念入手,深入到查询(Queries)、变更(Mutations)和订阅(Subscriptions)的实现,最后探讨如何在实际项目中部署和优化GraphQL服务。此外,本文还将简要介绍如何利用现有的GraphQL工具和库来加速开发过程。
|
27天前
|
XML JSON 安全
谈谈你对RESTful API设计的理解和实践。
RESTful API是基于HTTP协议的接口设计,通过URI标识资源,利用GET、POST、PUT、DELETE等方法操作资源。设计注重无状态、一致性、分层、错误处理、版本控制、文档、安全和测试,确保易用、可扩展和安全。例如,`/users/{id}`用于用户管理,使用JSON或XML交换数据,提升系统互操作性和可维护性。
18 4
|
1月前
|
消息中间件 缓存 API
微服务架构下的API网关性能优化实践
在现代的软件开发中,微服务架构因其灵活性和可扩展性被广泛采用。随着服务的细分与增多,API网关作为微服务架构中的关键组件,承担着请求路由、负载均衡、权限校验等重要职责。然而,随着流量的增长和业务复杂度的提升,API网关很容易成为性能瓶颈。本文将深入探讨API网关在微服务环境中的性能优化策略,包括缓存机制、连接池管理、异步处理等方面的具体实现,旨在为开发者提供实用的性能提升指导。
|
1月前
|
缓存 负载均衡 监控
构建高效微服务架构:API网关的作用与实践
【2月更文挑战第31天】 在当今的软件开发领域,微服务架构已成为实现系统高度模块化和易于扩展的首选方法。然而,随着微服务数量的增加,确保通信效率和管理一致性变得尤为重要。本文将探讨API网关在微服务架构中的核心角色,包括其在请求路由、安全性、负载均衡以及聚合功能方面的重要性。我们将通过具体案例分析,展示如何利用API网关优化后端服务,并讨论实施过程中的最佳实践和常见挑战。
|
1月前
|
搜索推荐 数据挖掘 API
1688商品详情API在电商平台中的应用与实践
随着电子商务的迅猛发展,越来越多的商家选择利用API(应用程序编程接口)来提升其在线业务的效率和用户体验。特别是在商品信息展示方面,1688商品详情API作为连接商家和消费者的重要桥梁,扮演着至关重要的角色。本文将深入探讨1688商品详情API的功能、应用场景以及如何通过该API提高电商平台的商品信息展示质量。
|
1月前
|
JSON API 数据格式
构建高效Python Web应用:Flask框架与RESTful API设计实践
【2月更文挑战第17天】在现代Web开发中,轻量级框架与RESTful API设计成为了提升应用性能和可维护性的关键。本文将深入探讨如何使用Python的Flask框架来构建高效的Web服务,并通过具体实例分析RESTful API的设计原则及其实现过程。我们将从基本的应用架构出发,逐步介绍如何利用Flask的灵活性进行模块化开发,并结合请求处理、数据验证以及安全性考虑,打造出一个既符合标准又易于扩展的Web应用。
651 4