套接字通信

背景

基于C语言,对linux系统下套接字通信相关的知识点进行梳理,比如重点概念的理解,重点操作函数的解析等,最后附上相关示例代码。

概念

套接字分类

  • 流式套接字(SOCK_STREAM)
  • 数据报套接字(SOCK_DGRAM)
  • 原始套接字

流式套接字

使用TCP(传输控制协议)进行数据传输,可以保证数据传输的准确性。

数据报套接字

使用UDP(使用者数据报协议)进行数据传输,不能保证接收的数据的准确性。

相关数据结构

struct sockaddr

#include <sys/socket.h>struct sockaddr
{
   unsigned short sa_family;//地址协议族
    char sa_data[14];//地址(ip + port)
};

  struct sockaddr 是通用的套接字地址,长度为16字节。

struct sockaddr_in

#include <netinet/in.h>
/* Internet address. */
struct in_addr
{
  uint32_t s_addr;
};
/* Structure describing an Internet socket address. */
struct sockaddr_in
{
  unsigned short sa_family;
  uint16_t sin_port; /* Port number. */必须是网络字节序
  struct in_addr sin_addr; /* Internet address. */必须是网络字节序
  unsigned char sin_zero[8];/* Pad to size of `struct sockaddr‘. */
};

  internet环境下套接字的地址形式,长度也是16字节;

  因为bind()函数的套接字地址类型是通用类型,所以现在通行的做法是,使用struct sockaddr_in绑定ip和端口,然后强转成struct sockaddr类型  

本机转换

由于struct sockaddr_in的Ip和端口是数据需要发送到网络端,所以类型必须是网络字节序;

端口的转换需要用到下面的htons

#include <arpa/inet.h>uint16_t htons(uint16_t hostshort);
uint32_t htonl(uint32_t hostlong);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

其实,ip的转换也可以用htonl,但入参是uint32_t,需要先将一个字符串类型的IP换算成数值类型再传参;
考虑到htonl的使用有些繁琐,一般我们使用下面的函数来进行地址的转换:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);

  inet_addr()和inet_aton()都可以用于获取一个网络字节序的地址;
  inet_ntoa是逆操作;

  

#define INADDR_ANY ((in_addr_t) 0x00000000)

  INADDR_ANY是一个宏定义,数值是网络字节序,等价于inet_addr("0.0.0.0"),功能是代码所有本机IP

socket()

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

  domain 网络通信协议族,一般写AF_INET
  type 通信类型,SOCK_STREAM|SOCK_DGRAM
  protocol 定义额外的一个通信协议。通常只需要一个协议,所以这里填0
  返回:成功返回一个可用套接字;失败返回-1,并重置errno

bind()

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);

  给套接字绑定到 “本机通信地址”返回:
  成功返回一个可用套接字;失败返回-1,并重置errno

connect()

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen); 

  将套接字与远程服务器通信地址绑定
  返回:成功返回一个可用套接字;失败返回-1,并重置errno

listen()

int listen(int sockfd, int backlog); 

  sockfd一般是服务器的网络侦听套接字,backlog是连接队列的长度(等待接受连接请求)
  返回:成功返0;失败返回-1并重置errno

accept()

#include <sys/types.h>
#include <sys/socket.h>
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

  返回一个成功建立连接的新套接字
  返回:成功返0;失败返回-1并设置errno

send()

#include <sys/types.h>
#include <sys/socket.h>
int send(int s, const void *msg, size_t len, int flags);
int sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
int sendmsg(int s, const struct msghdr *msg, int flags);

  s 套接字
  msg 待发送的数据
  len 数据长度
  flags 填0

close()

#include <unistd.h>
int close(int fd);

  完全关闭连接

 

#include <sys/socket.h>
int shutdown(int sockfd, int how);
    how:
    --SHUT_RD      关闭读端
    --SHUT_WR      关闭写端
    --SHUT_RDWR    关闭读写(同close())

  相比close,有更多的控制

示例代码

参考

原文地址:https://www.cnblogs.com/orejia/p/12128866.html

时间: 2024-11-03 11:36:30

套接字通信的相关文章

linux套接字通信之recv中的缓存机制的研究

以前一直有这么一个小小的疑惑,当一个进程注册一个套接字后,如果这个套接字没有被调用recv函数接受数据包,那么这个套接字能接受到数据包吗? 或者这样说,如果我的程序注册了一个套接字去接受数据包,但是每收到一个数据包都需要很长一段时间处理,并且在处理数据包的途中recv函数使没有被调用的,那么如果程序再处理数据包的途中有数据包到来,那我的程序会不会漏过这些数据包(那个包到达的时候程序在处理别的包,而没有调用recv函数)? 答案是不会的.事实上linux中会为每个套接字建立缓存,当属于套接字的包到

一起talk C栗子吧(第一百五十九回:C语言实例--基于AF_INET域的数据报套接字通信)

各位看官们,大家好,上一回中咱们说的是基于AF_INET域的流套接字通信的例子,这一回咱们说的例子是:基于AF_INET域的数据报套接字通信 .闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在上一回中一起制作了我们的第三道佳肴是:基于AF_INET域的流套接字通信.今天,我将和大家一起制作第四道佳肴:基于AF_INET域的数据报套接字通信. 制作第四道佳肴的菜谱:数据报套接字过程. 制作第四道佳肴的食材:数据报套接字的接口,套接字属性,套接字地址信息. 看官们,以上的内容,我们

一起talk C栗子吧(第一百五十七回:C语言实例--基于AF_UNIX域的数据报套接字通信)

各位看官们,大家好,上一回中咱们说的是基于AF_UNIX域的流套接字通信的例子,这一回咱们说的例子是:基于AF_UNIX域的数据报套接字通信 .闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在上一回中一起制作了我们的第一道佳肴是:基于AF_UNIX域的流套接字通信.今天,我将和大家一起制作第二道佳肴:基于AF_UNIX域的数据报套接字通信. 制作第二道佳肴的菜谱:数据报套接字过程. 制作第二道佳肴的食材:数据报套接字的接口,套接字属性,套接字地址信息. 看官们,以上的内容,我们

IPC——流套接字通信

Linux进程间通信——使用流套接字 前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网络编程,这里将会简单地讲述如何使用socket进行简单的网络编程. 一.什么是socket socket,即套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行.也就是说它可以让不在同一台计算机

一起talk C栗子吧(第一百五十六回:C语言实例--基于AF_UNIX域的流套接字通信)

各位看官们,大家好,上一回中咱们说的获取socket通信地址的例子,这一回咱们说的例子是:基于AF_UNIX域的流套接字通信 .闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在前面章回中介绍了套接字的通信过程以及套接字的的细节,总感觉还缺少些什么,一时还真是想不起来.这好比我们有了食谱也有了食材,那么我们就可以做一道美味的佳肴了.啊!有了.一提到美味的佳肴,灵感就来了.我们缺少的是对套接字的综合演练,也就是把前面章回中知识串在一起,然后举一个综合使用套接字知识进行套接字通信的例

一起talk C栗子吧(第一百五十八回:C语言实例--基于AF_INET域的流套接字通信)

各位看官们,大家好,上一回中咱们说的是基于AF_UNIX域的数据报套接字通信的例子,这一回咱们说的例子是:基于AF_INET域的流套接字通信 .闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在上一回中一起制作了我们的第二道佳肴是:基于AF_UNIX域的数据报套接字通信.今天,我将和大家一起制作第三道佳肴:基于AF_INET域的流套接字通信. 制作第三道佳肴的菜谱:流套接字过程. 制作第三道佳肴的食材:流套接字的接口,套接字属性,套接字地址信息. 看官们,以上的内容,我们在前面章

并发编程 - 协程 - 1.协程概念/2.greenlet模块/3.gevent模块/4.gevent实现并发的套接字通信

1.协程并发:切+保存状态单线程下实现并发:协程 切+ 保存状态 yield 遇到io切,提高效率 遇到计算切,并没有提高效率 检测单线程下 IO行为 io阻塞 切 相当于骗操作系统 一直处于计算协程:...单线程下实现并发:根本目标:遇到IO就切,一个线程的整体IO降下来程序用的cpu 时间长,就叫执行效率高效率最高:多个进程 (多个cpu) 每个进程开多个线程 每个线程用到协程 (IO就切)总结协程特点: 1 #并发执行 2 import time 3 4 def producer(): 5

27 Apr 18 GIL 多进程多线程使用场景 线程互斥锁与GIL对比 基于多线程实现并发的套接字通信 进程池与线程池 同步、异步、阻塞、非阻塞

27 Apr 18 一.全局解释器锁 (GIL) 运行test.py的流程: a.将python解释器的代码从硬盘读入内存 b.将test.py的代码从硬盘读入内存  (一个进程内装有两份代码) c.将test.py中的代码像字符串一样读入python解释器中解析执行 1 .GIL:全局解释器锁 (CPython解释器的特性) In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple na

python全栈脱产第37天------进程池与线程池、协程、gevent模块、单线程下实现并发的套接字通信

一.进程池与线程池 调用concurrent.futures下的ThreadPoolExecutor,ProcessPoolExecutor来实现 提交任务有两种方式:同步调用:提交完一个任务之后,就在原地等待,等待任务完完整整地运行完毕拿到结果后,在执行下一段代码,是串行的 异步调用:提交完一个任务之后,不在原地等待,直接运行下一段代码,任务是并发的 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutorimp

python 并发编程 基于gevent模块 协程池 实现并发的套接字通信

基于协程池 实现并发的套接字通信 客户端: from socket import * client = socket(AF_INET, SOCK_STREAM) client.connect(('127.0.0.1', 8080)) while True: msg = input(">>>:").strip() if not msg:break client.send(msg.encode("utf-8")) data = client.recv(