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. js千分位分隔,数字货币化方法学习记录

    js千分位分隔,数字货币化-4种方法(含正则) 方法1-整数货币化 // 整数货币化 function intCurrency(num) { var reg = new RegExp("^[ ...

  2. Go 和 Syscall

    曹春晖:谈一谈 Go 和 Syscall https://juejin.im/post/6844903845475139597

  3. Linux进程内存用量分析之堆内存篇

    https://mp.weixin.qq.com/s/a6mLMDinYQGUSaOsGYCEaA 独家|Linux进程内存用量分析之堆内存篇 姬晨烜 58技术 2019-12-06 导语 本文将介绍 ...

  4. KDB调试 — ARM

    1        寄存器 1.1         通用寄存器 A64指令集可以看到31个64位通用(整数)寄存器,分别是R0-R30. 在64位上下文中,这些寄存器通常使用名称x0-x30来表示; 在 ...

  5. vuex有哪几种属性

    有五种,分别是 State. Getter.Mutation .Action. Modulestate => 基本数据(数据源存放地)getters => 从基本数据派生出来的数据muta ...

  6. Redis下载及安装(windows版)

    下载地址1.Github下载地址:https://github.com/MicrosoftArchive/redis/releases2.百度网盘下载地址 https://pan.baidu.com/ ...

  7. JavaScript 类型、原型与继承学习笔记

    目录 一.概览 二.数据类型 1. JavaScript中的数据类型 2. 什么是基本类型(Primitive Data Type) 2.1 概念 2.2 七个基本类型 2.3 基本类型封装对象 3. ...

  8. brew更换国内源

    来源:清华大学开源软件镜像站(https://mirror.tuna.tsinghua.edu.cn/help/homebrew/) 替换现有上游 1 # brew 程序本身,Homebrew/Lin ...

  9. VS CODE远程办公篇一

    作者:良知犹存 转载授权以及围观:欢迎添加微信:becom_me 总述     因为疫情的来临,让远程办公变得原来越火.这次我也是盯上了这个功能,实现在家里远程配置电脑. 嵌入式Linux开发的程序员 ...

  10. P1908 逆序对——树状数组&离散化&快读快写の学习

    题目简述: 对于给定的一段正整数序列,逆序对就是序列中 a_i>a_jai​>aj​ 且 i<ji<j 的有序对. 输出序列中逆序对的数目. 知识补充: 树状数组: 这东西就是 ...