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函数应该用在调用socket和bind函数之后, 并且用在调用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

Socket编程实践(3) --Socket API的更多相关文章

  1. Socket编程实践(2) Socket API 与 简单例程

    在本篇文章中,先介绍一下Socket编程的一些API,然后利用这些API实现一个客户端-服务器模型的一个简单通信例程.该例子中,服务器接收到客户端的信息后,将信息重新发送给客户端. socket()函 ...

  2. Socket编程实践(2) --Socket编程导引

    什么是Socket? Socket可以看成是用户进程与内核网络协议栈的接口(编程接口, 如下图所示), 其不仅可以用于本机进程间通信,可以用于网络上不同主机的进程间通信, 甚至还可以用于异构系统之间的 ...

  3. C# socket编程实践

    C# socket编程实践——支持广播的简单socket服务器   在上篇博客简单理解socket写完之后我就希望写出一个websocket的服务器了,但是一路困难重重,还是从基础开始吧,先搞定C# ...

  4. Socket编程实践(6) --TCP服务端注意事项

    僵尸进程处理 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中添加 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法,解决僵尸进程 sign ...

  5. Socket编程实践(6) --TCPNotes服务器

    僵尸进程过程 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中加入 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法.解决僵尸进程 sign ...

  6. Socket编程实践(10) --select的限制与poll的使用

    select的限制 用select实现的并发服务器,能达到的并发数一般受两方面限制: 1)一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n(number)来调整或 ...

  7. Socket编程实践(1) 基本概念

    1. 什么是socket socket可以看成是用户进程与内核网络协议栈的编程接口.TCP/IP协议的底层部分已经被内核实现了,而应用层是用户需要实现的,这部分程序工作在用户空间.用户空间的程序需要通 ...

  8. C# socket编程实践——支持广播的简单socket服务器

    在上篇博客简单理解socket写完之后我就希望写出一个websocket的服务器了,但是一路困难重重,还是从基础开始吧,先搞定C# socket编程基本知识,写一个支持广播的简单server/clie ...

  9. C# Socket编程(4)初识Socket和数据流

    经过前面基础知识作为背景,现在对Socket编程进行进一步的学习.在System.Net.Socket命名空间提供了Socket类,利用该类我们可以直接编写Socket的客户端和服务的的程序.但是直接 ...

随机推荐

  1. GrideSearchCV 优化算法参数

    很多机器学习算法有参数,比如 linear_model.LogisticRegression()中有参数C. sklearn中的GrideSearchCV可方便调参过程.如下: import nump ...

  2. 打造适合你的ABP(1)---- 完善日志系统

    最近使用Abp开发了一个项目,对abp有一个大概的了解,第一个小项目接近尾声,新的项目马上开始,针对开发第一个项目中发现的问题及不方便的地方,本人做一些修改,特此记录,请大家多多指正! 本人的开发环境 ...

  3. 漫谈Web缓存架构

    计算机领域多处地方用到缓存,比如说为了缓解CPU和内存之间的速度不匹配问题,我们往往通过增加一级.二级.三级缓存,CPU先从缓存中取指令,如果取不到,再从内存中取,并更新缓存,同时,根据程序的局部性原 ...

  4. CF | Alyona and Mex

    Someone gave Alyona an array containing n positive integers a1, a2, ..., an. In one operation, Alyon ...

  5. 百钱买百鸡问题Java

    //百钱买百鸡public class baiqianbaiji { static void BQBJ(int m,int n)//m为钱的总数,n为鸡数 { int z; for(int x = 0 ...

  6. Redis之(二)数据类型及存储结构

    Redis支持五中数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及zset(sortedset:有序集合). Redis定义了丰富的原语命令,可以直接与Redis ...

  7. 一道有趣的Twitter技术面试题

    来自:http://blog.jobbole.com/50705/ 看下面这个图片” “在这个图片里我们有不同高度的墙.这个图片由一个整数数组所代表,数组中每个数是墙的高度.上边的图可以表示为数组[2 ...

  8. Android简易实战教程--第三十二话《使用Lrucache和NetworkImageView加载图片》

    转载本专栏每一篇博客请注明转载出处地址,尊重原创.此博客转载链接地址:小杨的博客    http://blog.csdn.net/qq_32059827/article/details/5279131 ...

  9. SpriteKit给游戏弹跳角色添加一个高度标示器

    这是一个类似于跳跃涂鸦的小游戏,主角不断吃能量球得到跳跃能量向更高的地方跳跃,如果图中碰到黑洞就挂了- 在游戏调试过程中如果能实时知道主角的高度就好了,这将有助于程序猿动态的判断游戏胜败逻辑. 你可以 ...

  10. UIKit中ImageView动画堆叠显示的微调整

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 网上看到一个PackingList项目(如果需要源代码可以Q我 ...