linux网络程序设计——1 socket的概念

       在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址+端口号”就称为socket。
  在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。socket本身有“插座”的意思,因此用来描述网络连
接的一对一关系。
  TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socketAPI。
  本章的主要内容是socket API,主要介绍TCP协议的函数接口,最后介绍UDP协议和UNIX Domain Socket的函数接口。



图1-1socket-api调用流程

1.1 基础知识

网络字节序

  我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。网络数据流同样有大端小端之分,那么如何定义网络数据流的地址呢?发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。

  TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。例如上一节的UDP段格式,地址0-1是16位的源端口号,如果这个端口号是1000(0x3e8),则地址0是0x03,地址1是0xe8,也就是先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe8。但是,如果发送主机是小端字节序的,这16位被解释成0xe803,而不是1000。因此,发送主机把1000填到发送缓冲区之前需要做字节序的转换。同样地,接收主机如果是小端字节序的,接到16位的源端口号也要做字节序的转换。如果主机是大端字节序的,发送和接收都不需要做转换。同理,32位的IP地址也要考虑网络字节序和主机字节序的问题。

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

//h表示hostn表示networkl表示32位长整数,s表示16位短整数。

//如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

IP地址转换函数

#include <arpa/inet.h>

int inet_pton(int af, const char *src, void *dst);//把字符串的ip转换成32位二进制的整型

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);//32位二进制的整型转成字符串的ip

//支持IPv4IPv6 可重入函数

其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr,因此函数接口是void *addrptr

sockaddr数据结构

strcut sockaddr 很多网络编程函数诞生早于IPv4协议,那时候都使用的是sockaddr结构体,为了向前兼容,现在sockaddr退化成了(void *)的作用,传递一个地址给函数,至于这个函数是sockaddr_in还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型。内存结构如下图所示:


struct sockaddr {

  sa_family_t sa_family; /* address family, AF_xxx */

  char sa_data[14]; /* 14 bytes of protocol address */

};

 

//ipv4

struct sockaddr_in {

    __kernel_sa_family_t sin_family; /* Address family */

    __be16 sin_port; /* Port number */

    struct in_addr sin_addr; /* Internet address */

    /* Pad to size of `struct sockaddr'. */

    unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -

    sizeof(unsigned short int) - sizeof(struct in_addr)];//填充字节

};

/* Internet address. */

struct in_addr {

    __be32 s_addr;

};

 

//ipv6

struct sockaddr_in6 {

    unsigned short int sin6_family; /* AF_INET6 */

    __be16 sin6_port; /* Transport layer port # */

    __be32 sin6_flowinfo; /* IPv6 flow information */

    struct in6_addr sin6_addr; /* IPv6 address */

    __u32 sin6_scope_id; /* scope id (new in RFC2553) */

};

 

struct in6_addr {

    union {

    __u8 u6_addr8[16];

    __be16 u6_addr16[8];

    __be32 u6_addr32[4];

    } in6_u;

 

    #define s6_addr in6_u.u6_addr8

    #define s6_addr16 in6_u.u6_addr16

    #define s6_addr32 in6_u.u6_addr32

};

 

//UNIX Domain Socket的地址格式

#define UNIX_PATH_MAX 108

struct sockaddr_un {

    __kernel_sa_family_t sun_family; /* AF_UNIX */

    char sun_path[UNIX_PATH_MAX]; /* pathname 类似于有名管道*/

};

Pv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位端口号和32位IP地址,IPv6地址用sockaddr_in6结构体表示,包括16位端口号、128位IP地址和一些控制字段。UNIXDomain Socket的地址格式定义在sys/un.h中,用sockaddr_un结构体表示。各种socket地址结构体的开头都是相同的,前16位表示整个结构体的长度(并不是所有UNIX的实现都有长度字段,如Linux就没有),后16位表示地址类型。IPv4、IPv6和Unix Domain Socket的地址类型分别定义为常数AF_INETAF_INET6AF_UNIX。这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容。因此,socket API可以接受各种类型的sockaddr结构体指针做参数,例如bind、accept、connect等函数,这些函数的参数应该设计成void *类型以便接受各种类型的指针,但是sock API的实现早于ANSI C标准化,那时还没有void *类型,因此这些函数的参数都用struct sockaddr *类型表示,在传递参数之前要强制类型转换一下,例如:

struct sockaddr_in servaddr;

/* initialize servaddr */

bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));//传递参数时强转 

1.2网络套接字API

1.2.1 socket()(构造出一条通道)

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

int socket(int domain, int type, int protocol);

 

domain:

  AF_INET6 //与上面类似,不过是来用IPv6的地址

  AF_UNIX //本地协议,使用在UnixLinux系统上,一般都是当客户端和服务器在同一台及其上的时候使用

  PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL   //UNIX 进程通信协议

  PF_INET/AF_INET      //Ipv4网络协议,这是大多数用来产生socket的协议,使用TCPUDP来传输,用IPv4的地址

  PF_INET6/AF_INET6    //Ipv6网络协议

  PF_IPX/AF_IPX IPX-Novell    //协议

  PF_NETLINK/AF_NETLINK   //核心用户接口装置

  PF_X25/AF_X25   //ITU-T X. 25/ISO-8208 协议

  PF_AX25/AF_AX25 //业余无线AX. 25 协议

  PF_ATMPVC/AF_ATMPVC //存取原始 ATM PVCs

  PF_APPLETALK/AF_APPLETALK   //appletalk (DDP)协议

  PF_PACKET/AF_PACKET //初级封包接口

type:

  SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。

  SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。

  SOCK_SEQPACKET 这个协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取

  SOCK_RAW 这个socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)

  SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数包的顺序

protocol:

  0 默认协议

返回值:

  成功返回一个新的文件描述符,失败返回-1,设置errno

socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。对于IPv4,domain参数指定为AF_INET。对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。

socket类型

当socket创建完之后,程序必须指定地址域和socket类型。两个进程能够相互通信,当且仅当它们的socket是相同类型的并且在相同的域。

有两种广泛使用的地址域,一种是Unix(unix domain),两个进程共享一套文件系统进行通信,另一种是互联网域(Internet domain),两个运行在互联网主机上的进程进行通信。这两种地址域有自己的地址格式。

Unix域中,socket的地址是文件系统中的字符串条目。

在互联网域中,socket的地址包含一个主机的网络地址(网络中的每台计算机都有一个唯一的32位地址,通常称为它的IP地址),另外,每一个socket需要一个主机的端口号。端口号是16位的无符号整形数。其中比较小的数是系统保留的,绑定一些标准服务。例如,FTP服务器的端口号是21.所有计算机上的标准服务都有相同的端口号十分重要,这样,客户端才能知道它们的地址,以方便连接。通常,大于2000的端口号是可用的。

有两种广泛使用的socket类型,一种是socket(stream socket),另一种是数据报socket(datagram socket)。socket把通信当做一个连续的字符串流,而数据报socket必须把整条信息一次读完。每种类型有他们自己的通信协议。

流socket使用TCP协议(transmissioncontrol protocol,传输控制协议),TCP协议是稳定的、面向流的协议;数据报socket使用UDP协议(Unix datagram protocol),UDP协议是不稳定的,并且是面向消息的。

1.2.2 bind()

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

 

//绑定后,若有用户访问addr地址时,会通过sockfd进行数据传递

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

 

sockfd:

    socket文件描述符

addr:

    构造出IP地址加端口号

addrlen:

    sizeof(addr)长度

返回值:

    成功返回0,失败返回-1, 设置errno。转到

服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接,因此服务器需要调用bind绑定一个固定的网络地址和端口号

bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。前面讲过,struct sockaddr *是一个通用指针类型,addr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度。

//sockaddr_in对象的设置

struct sockaddr_in servaddr;

bzero(&servaddr, sizeof(servaddr)); //置字节字符串前n个字节为零且包括‘\0’

servaddr.sin_family = AF_INET; //地址家族

servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //绑定ip地址,INADDR_ANY表示本机的任意一个IP地址都可以

servaddr.sin_port = htons(8000);//绑定端口

首先将整个结构体清零,然后设置地址类型为AF_INET,网络地址为INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址,端口号为8000。

 1.2.3 listen()

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

 

//sockfd所指向的socktet具有监听的能力

int listen(int sockfd, int backlog);

 

sockfd:

    socket文件描述符

backlog:

排队建立3次握手队列和刚刚建立3次握手队列的链接数和(默认为128)

返回值:

    成功返回0,失败-1并设置errno。转到

这个函数特别适用于同时有多个连接请求的服务器;

查看系统默认backlog:cat/proc/sys/net/ipv4/tcp_max_syn_backlog

典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态如果接收到更多的连接请求就忽略。listen()成功返回0,失败返回-1。

若客户端(ip+端口)向服务器发起链接,以下这些过程都是在内核进行的,在经过socket和bind函数后,服务器创建出一个socket(和ip+端口号绑定),在建立连接时候,TCP是通过三次握手建立,内核中会出两个队列,一个刚刚3次握手成功,另个是等待3次握手(三次握手整个过程没有完全完成)。队列长度有限,若队列满了,再来信号,报错RST。accept阻塞在socket,监听等待。若accept接受到连接,返回一个socket的文件描述符,专门用于和发起链接的客户端通信。connect负责发起连接,建立一个socket(会临时分配一个端口号),向服务端发数据。

 1.2.4 accept()

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

 

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

 

sockdf:

    socket文件描述符

addr:

    传出参数,返回链接客户端地址信息,含IP地址和端口号

addrlen:

    传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小(IPv4或IPv6)

返回值:

    成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno

三方握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-resultargument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。如果给addr参数传NULL,表示不关心客户端的地址。

  服务器程序结构是这样的:

while (1) {

    cliaddr_len = sizeof(cliaddr);

    connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

    n = read(connfd, buf, MAXLINE);

    ......

    close(connfd);

}

 1.2.5 connect()

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

 

sockdf:

    socket文件描述符

addr:

    传入参数,指定服务器端地址信息,含IP地址和端口号

addrlen:

    传入参数,传入sizeof(addr)大小

返回值:

    成功返回0,失败返回-1,设置errno

客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。connect()成功返回0,出错返回-1。

 1.2.6 tcp数据读写

recv(int fd,void*buf,size_t len,int flags)

send(int fd,const void *buf,size_t len,int flags)

flag 有一些特别的参数

    持续监听对方的回应

     不经过路由表

     对socket非阻塞

     发送紧急数据

     不接受sig信号等等

 1.2.7 udp数据读写

recvfrom(int fd,void*buf,size_t len,int flags,struct sockaddr * my_addr, int addrlen)

sendto(int fd,const void*buf,size_t len,int flags,struct sockaddr * my_addr, int addrlen)

 1.2.8 通用数据读写

recvmsg(int fd,struct msghdr*msg,int flags);

sendmsg(int fd,struct msghdr*msg,int flags);

struct msghdr

{

    void* msg_name;

    socklen_t msg_namelen;

    struct iovec*msg_iov;

    int msg_iovlen;

    void* msg_control;

    socklen_t msg_controllen;

    int msg_flags;

};

 

struct iovec

{

    void *iov_base;

    size_t iov_len;

};

 readv和writev

readv和writev函数是Linux中的两个系统调用,类似于read和write函数,不同的是,readv和writev在一次执行过程中可以原子地作用于多个缓冲区,这些缓冲区常常是非连续的。readv和writev的原型如下:

#include <sys/uio.h>

 

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);

ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

 

struct iovec {

    void  *iov_base;    /* Starting address */

    size_t iov_len;     /* Number of bytes to transfer */

};

 

参数

int fd:是个文件描述符,

const struct iovec *iov:是指向iovec数据结构的一个指针,其中iov_base为缓冲区首地址,iov_len为缓冲区长度;

int iovcnt:指定了iovec的个数。

返回值

函数调用成功时返回读、写的总字节数,失败时返回-1并设置相应的errno。

在一次函数调用中,writev以顺序iov[0]、iov[1]至iov[iovcnt-1]从各缓冲区中聚集输出数据到fd,readv则将从fd读入的数据按同样的顺序散布到各缓冲区中,readv总是先填满一个缓冲区,然后再填下一个,因此,writev称为gather output,readv称为scatter input。

 先来看一个writev的例子,指定了两个缓冲区,str0和str1,内容输出到标准输出,并打印实际输出的字节数。

// writevex.c

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <sys/uio.h>

 

int main()

{

    char *str0 = "hello ";

    char *str1 = "world\n";

    struct iovec iov[2];

    ssize_t nwritten;

 

    iov[0].iov_base = str0;

    iov[0].iov_len = strlen(str0);

    iov[1].iov_base = str1;

    iov[1].iov_len = strlen(str1);

 

    nwritten = writev(STDOUT_FILENO, iov, 2);

    printf("%ld bytes written.\n", nwritten);

 

    exit(EXIT_SUCCESS);

}

 1.2.9带外标记判断

int sockatmark(int sockfd);

 1.2.10地址信息函数

int getsockname(int socketfd,struct sockaddr * my_addr, int addrlen);//本端的地址信息

int getpeername(int socketfd,struct sockaddr * my_addr, int addrlen);//远端的地址信息

 1.2.11 socket选项

//获取socket选项

getsockopt(int socketfd,int opt_name,void* option_value,socket_t restrict option_len)

//设置socket选项

getsockopt(int socketfd,int opt_name,void* option_value,socket_t restrict option_len)

选项名称        说明                  数据类型

========================================================================

SOL_SOCKET

------------------------------------------------------------------------

SO_BROADCAST      允许发送广播数据            int

SO_DEBUG        允许调试                int

SO_DONTROUTE      不查找路由               int

SO_ERROR        获得套接字错误             int

SO_KEEPALIVE      保持连接                int

SO_LINGER        延迟关闭连接              struct linger

SO_OOBINLINE      带外数据放入正常数据流         int

SO_RCVBUF        接收缓冲区大小             int

SO_SNDBUF        发送缓冲区大小             int

SO_RCVLOWAT       接收缓冲区下限             int

SO_SNDLOWAT       发送缓冲区下限             int

SO_RCVTIMEO       接收超时                struct timeval

SO_SNDTIMEO       发送超时                struct timeval

SO_REUSERADDR      允许重用本地地址和端口         int

SO_TYPE         获得套接字类型             int

SO_BSDCOMPAT      与BSD系统兼容              int

========================================================================

IPPROTO_IP

------------------------------------------------------------------------

IP_HDRINCL       在数据包中包含IP首部          int

IP_OPTINOS       IP首部选项               int

IP_TOS         服务类型

IP_TTL         生存时间                int

========================================================================

IPPRO_TCP

------------------------------------------------------------------------

TCP_MAXSEG       TCP最大数据段的大小           int

TCP_NODELAY       不使用Nagle算法             int

========================================================================

 1.2.12获取主机信息

//根据名字获取主机信息

struct hostent* gethostbyname(const char *name)

//根据ip获取主机信息

struct hostent* gethostbyaddr(const void *addr,size_t len,int type)

struct hostent

{

    char *h_name;//主机名

    char** h_aliases;//主机别名,可能有多个

    int h_addrtype;//地址类型

    int h_length;// 地址长度

    char ** h_addr_list//按照网络字节序列列出idp地址列表

}

 1.2.13获取服务信息

//根据 名字,端口号获取服务信息

struct servent*getservbyname(const char *name,const char *proto);

//根据服务类型,端口号获取服务信息

struct servent*getservbyport(int port,const char *proto);

struct servent{

    char *h_name;//主机名

    char** h_aliases;//主机别名,可能有多个

    int  s_port;//端口号

    char *s_proto;//服务类型,tcp或者upd等

}

 1.2.14通过主机名获取ip地址

int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );

 1.2.15通过socket地址获取主机名

int getnameinfo (const struct sockaddr *sockaddr, socklen_t addrlen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);

 1.2.16 套接字关闭shutdown / close

(1)shutdown

#include <sys/socket.h>

// 可以是全双工的sockfd部分或全部停工

int shutdown(int sockfd, int how);

参数:

int sockfd: 要操做的套接字,要求有效

int how:

  SHUT_RD(0): 关闭sockfd上的读功能,将不允许sockfd进程读操作

  SHUT_WR(1): 关闭sockfd的写功能,将不允许sockfd进行写操作

  SHUT_RDWR(2): sockfd不再可读可写

 

返回值:

On success, zero is returned. 

On error, -1 is returned, and errno is set appropriately.

EBADF 

sockfd is not a valid file descriptor.

EINVAL

An invalid value was specified in how (but see BUGS).

ENOTCONN

The specified socket is not connected.

ENOTSOCK

The file descriptor sockfd does not refer to a socket.

(2)close

#include <unistd.h>

//关闭一个打开的文件描述符

int close(int fd);

返回:

close() returns zero on success. 

On error, -1 is returned, and errno is set appropriately.

EBADF 

fd isn't a valid open file descriptor.

EINTR 

The close() call was interrupted by a signal; see signal(7).

EIO

An I/O error occurred.

ENOSPC,

EDQUOT

On NFS, these errors are not normally reported against the first write which exceeds the available storage space, but instead against a subsequent write(2), fsync(2), or close(2).

(3)close与shutdown区别

l  close终止了数据传送的两个方向

l  shutdown可以有选择的指针某个方向的数据传送或者终止数据传送的两个方向

l  shutdown how=SHUT_WR就可以保证对等方接受到一个EOF字符,而不管其他进程是否已经打开了套接字。而close不能保证,直到套接字引用计数减为0时才发送。也就是说直到所有的进程都关闭了套接字,才会发送EOF。

例如:

int conn = accept(sock, NULL, NULL);

pid_t pid = fork();

if(pid == -1)

  exit(EXIT_FAILURE);

if(pid == 0){ //子进程

  close(sock);

  //通信

  close(conn); //这时才会向对方发送FIN段(因为这个时候conn引用记数减为0

}

else if(pid > 3){ //父进程

     close(conn); //不会向客户端发送FIN段,仅仅是将套接字的引用记数减1

}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python是一种非常流行的编程语言,可以用于实现各种网络程序设计,其中包括socket网络程序设计。下面是我用300字中文回答该问题的解答: Python的socket模块提供了一组函数和类,用于实现网络通信。它允许我们创建不同类型的套接字,如TCP套接字或UDP套接字,并使用这些套接字进行数据的发送和接收。我们可以使用socket模块中的函数来创建服务器端和客户端,以及处理网络连接。我们可以指定主机名、端口号和通信协议来创建套接字,并使用绑定、监听和接受连接等方法来实现服务器端代码。对于客户端代码,我们可以使用套接字连接到服务器并发送和接收数据。 当我们实现了socket网络程序时,我们可以使用Wireshark这样的网络协议分析器来捕获和分析网络数据包。Wireshark可以捕获计算机上的网络流量,并显示详细的协议信息。我们可以使用Wireshark在网络数据链路层、网络层和传输层查看到底是如何发送数据的,以及数据的正确性。 为了使用Wireshark捕获Python实现的socket网络程序的数据包,我们需要正确配置Wireshark,以便捕获与我们正在运行的网络程序相关的流量。我们可以选择具体的本地网卡或仅捕获特定目标IP地址的流量。一旦我们设置好了Wireshark并开始捕获网络流量,我们可以通过筛选器来过滤出与我们的网络程序相关的数据包。从捕获的数据包中,我们可以看到各种协议的详细信息,如TCP、UDP或IP协议的头部字段,以及数据的内容。 总之,Python可以通过socket模块实现各种类型的网络程序设计,而Wireshark则可以用来捕获和分析这些网络程序的数据包,让我们能够更好地了解网络通信的细节。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值