Socket编程实践(3) --Socket API
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的更多相关文章
- Socket编程实践(2) Socket API 与 简单例程
在本篇文章中,先介绍一下Socket编程的一些API,然后利用这些API实现一个客户端-服务器模型的一个简单通信例程.该例子中,服务器接收到客户端的信息后,将信息重新发送给客户端. socket()函 ...
- Socket编程实践(2) --Socket编程导引
什么是Socket? Socket可以看成是用户进程与内核网络协议栈的接口(编程接口, 如下图所示), 其不仅可以用于本机进程间通信,可以用于网络上不同主机的进程间通信, 甚至还可以用于异构系统之间的 ...
- C# socket编程实践
C# socket编程实践——支持广播的简单socket服务器 在上篇博客简单理解socket写完之后我就希望写出一个websocket的服务器了,但是一路困难重重,还是从基础开始吧,先搞定C# ...
- Socket编程实践(6) --TCP服务端注意事项
僵尸进程处理 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中添加 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法,解决僵尸进程 sign ...
- Socket编程实践(6) --TCPNotes服务器
僵尸进程过程 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中加入 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法.解决僵尸进程 sign ...
- Socket编程实践(10) --select的限制与poll的使用
select的限制 用select实现的并发服务器,能达到的并发数一般受两方面限制: 1)一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n(number)来调整或 ...
- Socket编程实践(1) 基本概念
1. 什么是socket socket可以看成是用户进程与内核网络协议栈的编程接口.TCP/IP协议的底层部分已经被内核实现了,而应用层是用户需要实现的,这部分程序工作在用户空间.用户空间的程序需要通 ...
- C# socket编程实践——支持广播的简单socket服务器
在上篇博客简单理解socket写完之后我就希望写出一个websocket的服务器了,但是一路困难重重,还是从基础开始吧,先搞定C# socket编程基本知识,写一个支持广播的简单server/clie ...
- C# Socket编程(4)初识Socket和数据流
经过前面基础知识作为背景,现在对Socket编程进行进一步的学习.在System.Net.Socket命名空间提供了Socket类,利用该类我们可以直接编写Socket的客户端和服务的的程序.但是直接 ...
随机推荐
- Mysql B-Tree, B+Tree, B*树介绍
[摘要] 最近在看Mysql的存储引擎中索引的优化,神马是索引,支持啥索引.全是浮云,目前Mysql的MyISAM和InnoDB都支持B-Tree索引,InnoDB还支持B+Tree索引,Memory ...
- 解决使用web开发手机网页关于分辨率被缩放的坑
问题的产生 因为各方面原因,要用网页做界面,开发一个APP.内核使用的是腾讯的x5内核. 把外壳交给前端和设计测试的时候,都汇报:状态栏的颜色太不搭配了,要求可修改 遂启用了安卓4.4版本开始支持的沉 ...
- block的那些事(从懵懂到使用)
从大学开始自学iOS,在iOS岗位已经两年了,遇到传值等操作,代理和block二选一的话,以前我会毫不犹豫选择代理.久而久之,入职到大公司之后,发现处处是block的天地,才慢慢的了解block并爱上 ...
- 安卓高级 Android图片缓存之初识Glide
前言: 前面总结学习了图片的使用以及Lru算法,今天来学习一下比较优秀的图片缓存开源框架.技术本身就要不断的更迭,从最初的自己使用SoftReference实现自己的图片缓存,到后来做电商项目自己的实 ...
- Bootstrap3 栅格系统-媒体查询
在栅格系统中,我们在 Less 文件中使用以下媒体查询(media query)来创建关键的分界点阈值. /* 超小屏幕(手机,小于 768px) */ /* 没有任何媒体查询相关的代码,因为这在 B ...
- markdown绘图插件----mermaid简介
作者:黄永刚 mermaid简介 当撰写文档的时候,对于流程图的生成大多使用Visio等繁重的工具,没有一种轻便的工具能够画图从而简化文档的编写,就像markdown那样. mermaid解决这个痛点 ...
- Mybatis源码分析之参数映射及处理ParameterHandler
ParameterHandler是用来设置参数规则的,当StatementHandler调用prepare方法之后,接下来就是调用它来进行设置参数. ParameterHandler接口: publi ...
- ERP各个模块的缩写
财务系统模块: Oracle 总帐管理(GL) Oracle 应付帐管理(AP) Oracle 固定资产管理(FA) Oracle 应收帐管理(AR) Oracle 现金管理(CE) Oracle 项 ...
- 关于activitygroup过时,用frament替换操作
现在Fragment的应用真的是越来越广泛了,之前Android在3.0版本加入Fragment的时候,主要是为了解决Android Pad屏幕比较大,空间不能充分利用的问题,但现在即使只是在手机上, ...
- iOS下JS与原生OC互相调用(总结)
这是去年总结的一篇文章,也一并先放到这个目录下好了. iOS开发免不了要与UIWebView打交道,然后就要涉及到JS与原生OC交互,今天总结一下JS与原生OC交互的两种方式. JS调用原生OC篇 方 ...