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


目录
相关文章
|
9天前
|
网络协议 Python
Python网络编程基础(Socket编程)创建UDP socket对象
【4月更文挑战第8天】在Python中创建UDP服务器涉及使用`socket`模块创建socket对象,如`udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)`,然后绑定到特定IP地址和端口,如`udp_socket.bind((&#39;localhost&#39;, 12345))`。服务器通过`recvfrom`在无限循环中监听和接收数据报。这只是基础,实际应用还需处理接收、解析、响应及错误处理等。接下来可学习如何利用socket对象进行数据交互以构建完整服务器。
|
9天前
|
网络协议 网络性能优化 开发者
Python网络编程基础(Socket编程)UDP Socket编程
【4月更文挑战第8天】Python网络编程中,UDP与TCP协议各有特点。TCP提供可靠连接,确保数据顺序与完整性,适合文件传输等;UDP则无连接,速度快,常用于实时音视频,牺牲了数据可靠性。Python的socket库支持两者,开发者可根据需求选择。
|
4天前
|
缓存 负载均衡 算法
构建高效微服务架构:API网关的设计与实践
【5月更文挑战第20天】 在微服务架构中,API网关作为系统入口,承担着请求路由、负载均衡、权限校验等关键职责。本文将深入探讨如何设计一个高性能且易于扩展的API网关,并分享在实际项目中的实践心得。通过分析API网关的核心组件和常见挑战,我们将讨论优化策略,包括但不限于缓存机制、限流算法以及服务熔断。文章最终旨在提供一套可行的解决方案,帮助开发者构建出既健壮又灵活的后端服务架构。
|
9天前
|
缓存 负载均衡 API
微服务架构下的API网关性能优化实践
【5月更文挑战第10天】在微服务架构中,API网关作为前端和后端服务之间的关键枢纽,其性能直接影响到整个系统的响应速度和稳定性。本文将探讨在高并发场景下,如何通过缓存策略、负载均衡、异步处理等技术手段对API网关进行性能优化,以确保用户体验和服务的可靠性。
|
9天前
|
存储 算法 网络协议
【探索Linux】P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )
【探索Linux】P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )
18 0
|
9天前
|
存储 缓存 JavaScript
深入理解RESTful API设计原则与实践
【5月更文挑战第7天】在现代Web服务开发中,表述性状态传递(REST)是一种广泛采用的架构风格,用于构建可扩展的网络应用程序接口(APIs)。本文将探讨RESTful API的核心设计原则,并通过具体实例展示如何实现一个符合REST约束的后端服务。我们将讨论资源的识别、客户端-服务器通信模式、无状态性、以及统一接口的重要性,并探索如何使用当前的流行技术栈来实现这些概念。
|
9天前
|
JSON API 数据格式
淘宝商品评论数据获取:从API调用到应用实践
在电商的世界里,用户评论是洞察商品质量的一扇窗。淘宝,作为中国最大的在线购物平台,其海量的商品评论数据尤为宝贵。本文将带您走进淘宝商品评论数据的获取之旅,从API调用的基础知识到实际应用的代码示例,一探究竟。
|
9天前
|
消息中间件 缓存 算法
构建高效的后端API:优化方法与实践
随着互联网技术的迅速发展,构建高效的后端API已成为现代软件开发中的重要挑战。本文将探讨一些优化方法与实践,以帮助开发人员提高后端API的性能和可靠性。我们将讨论如何通过缓存、异步处理、数据库优化以及代码优化等方式来提升后端API的响应速度和吞吐量,从而为用户提供更好的体验。
|
9天前
|
XML JSON 安全
谈谈你对RESTful API设计的理解和实践。
RESTful API是基于HTTP协议的接口设计,通过URI标识资源,利用GET、POST、PUT、DELETE等方法操作资源。设计注重无状态、一致性、分层、错误处理、版本控制、文档、安全和测试,确保易用、可扩展和安全。例如,`/users/{id}`用于用户管理,使用JSON或XML交换数据,提升系统互操作性和可维护性。
21 4
|
9天前
|
负载均衡 监控 安全
构建高效微服务架构:API网关的作用与实践
在当今的软件开发中,微服务架构因其灵活性和可扩展性而受到青睐。然而,随之而来的复杂性也给维护和性能带来了挑战。本文探讨了API网关在微服务架构中的关键作用,包括请求路由、负载均衡、安全性控制以及限流熔断等方面。通过具体案例分析,我们展示了如何实现一个高性能的API网关,以支持动态的后端服务,并确保系统的高可用性和安全性。
35 2