Linux socket编程

套接字定义描述


套接字的域


  • AF_INET ====>IPv4
  • AF_INET6 ====>IPv6
  • AF_UNIX ====>unix 域
  • AF_UPSPEC ====>未使用

套接字的类型

  • SOCK_DGRAM ====>固定长度,无链接的,不可靠的报文传递
  • SOCK_RAM ====>IP协议数据报接口
  • SOCK_SEQPACKET====>固定长度,有序,可靠的,面向连接的报文传递
  • SOCK_STREAM ====>有序的,可靠的,双向的,面向连接的字节流

协议类型

  • IPPROTO_IP ====>IPV4协议族
  • IPPROTO_IPV6 ====>IPV6协议族
  • IPPROTO_ICMP ====>控制报文协议
  • IPPROTO_RAM ====>原始IP数据包
  • IPPROTO_TCP ====>字节流传输控制协议
  • IPPROTO_UDP ====>用户数据包协议

API

头文件

#include <sys/socket.h>

字节序

以太网中的字节序是大端的,因此相关的以太网的数据在小端机器上需要使用相关接口转换为以太网字节序。常用转换工具函数:

//4字节整形变量主机字节序的转换为网络字节序
uint32_t htonl(uint32_t hostint32);
//2字节整形变量主机字节序的转换为网络字节序
uint16_t htons(uint15_t hostint16);
//和上面相反
uint32_t ntohl(uint32_t netint32);
//和上面相反
uint32_t ntohl(uint32_t netint32);

常用接口(具体使用man 2 xxx 命令查看具体说明)

//创建套接字
int socket(int domain,int type,int protocol);
//将一个套接字和指定地址和端点关联起来
int bind(int sockfd,const struct sockaddr * addr,socklen_t addrlen);
//开始监听这个套接字
int listen(int socket, int backlog);
//向指定socket发起连接请求
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//接收监听到的一个socket连接请求
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//通过socket 发送数据,地址是socket默认
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//通过socket 接收数据,地址为socket 默认
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//通过socket 发送数据,地址是由参数指定
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
//通过socket 接收数据,地址由参数指定
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
//常用在unix 域下的进程通讯,发送数据
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
//常用在unix 域下的进程通讯,接收数据
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
//获取当前socket信息
int getsockname((int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//获取原端socket信息(建立连接之后)
int getpeername((int sockfd, const struct sockaddr *addr, socklen_t addrlen);

关闭套接字

套接字关闭可以像关闭一个文件的描述符一样调用close()接口来关闭socket接口,除此之外还可以使用shutdown接口进行更加细致的关闭操作:

sockfd :sock描述符
how :SHUT_RDWR 读写两端都关闭
: SHUT_WR 关闭写端
: SHUT_RD 关闭读端
返回值 :成功返回0 失败返回-1
int shutdown(int sockfd,int how);

相关结构体

//描述网络信息
struct sockaddr_in {
s_add.sin_family = AF_INET;
s_add.sin_port = htons(1040);
s_add.sin_addr.s_addr = inet_addr("127.0.0.1");
};

TCP服务端配置过程

  • 建立套接字,返回套接字
    //建立 IPv4域下的字节流服务的TCP协议的socket
    int sockfd_s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  • 将套接字和指定地址关联,使用上述的结构体描述端口和地址信息。
    //将这个socket个特定地址何端口关联起来
    bind(sockfd_s,(struct sockaddr*)&s_add,sizeof(struct sockaddr_in))
  • 告诉系统套接字刻意监听链接。
    //开始监听
    listen(sockfd_s,1)
  • 接受一个连接,这一步将返回新的套接字接口
    //接受任意连接请求,返回可以用来数据传输的socket描述符
    accept(sockfd_s,NULL,NULL);

TCP客户端配置过程

  • 建立套接字,返回套接字
    //建立 IPv4域下的字节流服务的TCP协议的socket
    int sockfd_s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  • 连接到指定地址何端口
    //向制定地址和端口发起链接请求
    connect(sockfd_c,(struct sockaddr*)&c_add,sizeof(c_add))

示例代码

见文末

连接信息获取

获取本地套接字信息

获取远端套接字信息(连接后)

套接字选项

  • 选项 类型(非特殊为int型) 描述
  • SO_ACCEPTCONN 查询套接字是否可以被监听
  • SO_BROADCAST 非0 广播数据报
  • SO_DEBUG 非0 启用调试
  • SO_ERROR 返回挂起套接字的错误并清除
  • SO_KEEPALIVE 非0 启用keep-alive报文
  • SO_OOBINLINE TCP 带外数据
  • SO_RCVBUF 获取接收缓冲区的数据
  • SO_RCVLOWAT 接受调用返回的最小字节数
  • SO_RCVTIMEO struct timeval 接收调用的超时时间
  • SO_REUSEADDR 重用地址,有用
  • SO_SNDBUF 发送buf中的字节数
  • SO_SNDLOWAT 发送传送的最小字节数
  • SO_SNDTIMEO struct timeval 发送超时时间
  • SO_TYPE 套接字类型标识,仅get可用
设置选项
int setsockopr(int sockfd,int level,int option,void *val,socklen_t len);
获取选项
int setsockopr(int sockfd,int level,int option,void *val);

带外数据

是一些通讯协议支持的可选功能,与普通数据相比其具有更高的优先级被传输。目前TCP的支持带外数据传输的,仅支持一个字节的紧急数据。有些实现TCP的带外数据还可以产生SIGURG信号。还可以通过下面的接口判断是否有紧急数据,当有紧急数据时,返回1。

iny sockatmark(int sockfd);

异步socket和非阻塞socket

基本上socket的异步IO和阻塞和非阻塞的处理和普通的文件基本相同,但是有一些区别的是,但是目前还没有完整的标准,视具体平台的实现情况。

示例demo

    int main(int argc,int *argv)
{
char *name,i;
struct hostent* host;
size_t len = sysconf(_SC_HOST_NAME_MAX);
if(len>0){
name = malloc(len+1);
}else{
name = malloc(1024);
len = 1024;
}
printf("Buff size%ld\n",stdout->_IO_buf_end-stdout->_IO_buf_base);
if(gethostname(name,len)<0){
printf("gethostname error!\n");
}
host = gethostbyname(name);
if(*host->h_aliases){
printf("%s\n%s\n%s\n%d\n",
host->h_name,//host name
*host->h_aliases, //host_name aliases
(host->h_addrtype==AF_INET?"IP_V4":"IP_V6"),
host->h_length);
}else{
printf("%s\n%s\n%d\n",
host->h_name,
(host->h_addrtype==AF_INET?"IP_V4":"IP_V6"),
host->h_length);
}
for(i=0;host->h_addr_list[i] != NULL;i++){
printf("%s\n",inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
}
printf("befor the fork call\n\n");
int pid = fork();
if(pid){
int status,temp=1;
int sockfd_s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sockfd_s<0){
goto fail;
}
if(setsockopt(sockfd_s,SOL_SOCKET,SO_REUSEADDR,&temp,sizeof(int)) < 0)
{
perror("setsockopt");
}
struct sockaddr_in s_add;
s_add.sin_family = AF_INET;
s_add.sin_port = htons(1040);
s_add.sin_addr.s_addr = inet_addr("127.0.0.1");
// inet_pton(AF_INET,"127.0.0.1",&s_add.sin_addr);
if(bind(sockfd_s,(struct sockaddr*)&s_add,sizeof(s_add))<0){
printf("1\n");
goto fail;
}
if(listen(sockfd_s,1)<0){
goto fail;
}
int c_fd = accept(sockfd_s,NULL,NULL);
if(c_fd < 0){
goto fail;
}
int len=sizeof(s_add);
if(getpeername(c_fd,(struct sockaddr*)&s_add,&len)<0){
printf("2\n");
goto fail;
}
printf("server:\n%s\n%d\n",inet_ntoa(s_add.sin_addr),ntohs(s_add.sin_port));
if(c_fd){
while(1){
char buf[64];
recv(c_fd,buf,64,0);
printf("%s\n",buf);
sleep(1);
}
}
fail:
close(sockfd_s);
perror(strerror(errno));
kill(pid,9);
waitpid(pid,&status,0);
printf("server end\n");
return 0;
}else if(!pid){
sleep(3);
int sockfd_c = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sockfd_c<0){
goto fail_c;
}
struct sockaddr_in c_add;
c_add.sin_family = AF_INET;
c_add.sin_port = htons(1040);
c_add.sin_addr.s_addr = inet_addr("127.0.0.1");
// inet_pton(AF_INET,"127.0.0.1",&c_add.sin_addr);
if(connect(sockfd_c,(struct sockaddr*)&c_add,sizeof(c_add))){
goto fail_c;
}
struct sockaddr_in d_add;
int len=sizeof(d_add); if(getpeername(sockfd_c,(struct sockaddr*)&d_add,&len)<0){
goto fail_c;
}
printf("cliens\n%s\n%d\n",inet_ntoa(d_add.sin_addr),ntohs(d_add.sin_port));
while(1)
{
send(sockfd_c,"hello word!\n",strlen("hello word!\n"),0);
sleep(1);
}
fail_c:
close(sockfd_c);
perror(strerror(errno));
_exit(0);
}
return 0;
}

Linux 应用开发----socket编程笔记的更多相关文章

  1. C# Socket编程笔记(转)

    C# Socket编程笔记 http://www.cnblogs.com/stg609/archive/2008/11/15/1333889.html TCP Socket:Server 端连接步骤: ...

  2. Linux学习之socket编程(二)

    Linux学习之socket编程(二) 1.C/S模型——UDP UDP处理模型 由于UDP不需要维护连接,程序逻辑简单了很多,但是UDP协议是不可靠的,实际上有很多保证通讯可靠性的机制需要在应用层实 ...

  3. Linux学习之socket编程(一)

    socket编程 socket的概念: 在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址+端口号”就称为socket. 在TCP协议中,建立连接的两个进 ...

  4. iOS开发— Socket编程

    Socket编程 一.了解网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被 ...

  5. python3全栈开发-socket编程

    一. 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端为你提供视 ...

  6. python socket编程笔记

    用python实现一个简单的socket网络聊天通讯 (Linux --py2.7平台与windows--py3.6平台) 人生苦短之我用Python篇(socket编程) python之路 sock ...

  7. Linux下Golang Socket编程原理分析与代码实现

    在POSIX标准推出后,socket在各大主流OS平台上都得到了很好的支持.而Golang是自带Runtime的跨平台编程语言,Go中提供给开发者的Socket API是建立在操作系统原生Socket ...

  8. Java套接字socket编程笔记

    相对于C和C++来说,Java中的socket编程是比较简单的,比较多的细节都已经被封装好了,每次创建socket连接只需要知道地址和端口即可. 在了解socket编程之前,我们先来了解一下读写数据的 ...

  9. 网络编程学习笔记:linux下的socket编程

    socket是进程通信的一种方式,通过调用一些API可以实现进程间通信,建立连接以及收发信息的过程如下图所示: 这些函数的用法如下: 1.int socket(int protocolFamily, ...

随机推荐

  1. Ansible自动化运维工具的使用

                                 Ansible自动化运维工具的使用       host lnventory 管理主机 ip  root账号密码 ssh端口 core mod ...

  2. IDEA SSM后端框架入门

    SSM框架 如果对SSM一无所知,推荐先去看这本书,可以在微信读书上看. 知识点 控制器返回对象时,对象需要有getter,setter方法,才能自动转化为json数据类型. 一个服务管理者对应多个业 ...

  3. Unix Socket 代理服务 unix域套接字

    基于Unix Socket的可靠Node.js HTTP代理实现(支持WebSocket协议) - royalrover - 博客园 https://www.cnblogs.com/accordion ...

  4. LOJ10013曲线

    题目描述 明明做作业的时候遇到了n  个二次函数s_i(x)=ax^2+bx+c ,他突发奇想设计了一个新的函数 f(x)=max{s_i(x)},i=1,2,...,n. 明明现在想求这个函数在 [ ...

  5. SSRF漏洞挖掘利用技巧

    参考文章 SSRF漏洞(原理&绕过姿势) SSRF绕过方法总结 SSRF绕过IP限制方法总结 Tag: #SSRF Ref: 概述 总结 利用一个可以发起网络请求的服务当作跳板来攻击内部其他服 ...

  6. Kepware软件基本操作及使用Java Utgard实现OPC通信

    一.环境搭建(基于win10 64位专业版) 1.Kepware 的下载.安装及使用 https://www.cnblogs.com/ioufev/p/9366877.html 2.重要:OPC 和 ...

  7. Spark踩坑填坑-聚合函数-序列化异常

    Spark踩坑填坑-聚合函数-序列化异常 一.Spark聚合函数特殊场景 二.spark sql group by 三.Spark Caused by: java.io.NotSerializable ...

  8. Linux常用命令,目录解析,思维导图

    文章目录 下载地址 Linux常用命令 linux系统常用快捷键及符号命令 Linux常用Shell命令 Linux系统目录解析 Shell Vi全文本编辑器 Linux安装软件 Linux脚本编制编 ...

  9. 文本处理三剑客简介(grep、awk、sed)

    本章内容: 命令 描述 awk 支持所有的正则表达式 sed 默认不支持扩展表达式,加-r 选项开启 ERE,如果不加-r 使用花括号要加转义符\{\} grep 默认不支持扩展表达式,加-E 选项开 ...

  10. javascript脚本何时会被执行

    javascript脚本可以嵌入在html内的任意地方,但它何时被调用呢?当浏览器打开HTML文件后,会直接运行不是声明函数的脚本或通过事件调用脚本函数,下面分析这几种情况. 1.浏览器在打开页面时执 ...