【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

这篇具有很好参考价值的文章主要介绍了【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

橙色

1、socket套接字介绍

所谓套接字,就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。

一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进程通信的接口,是应用程序与网络协议进行交互的接口。

它是网络环境中进行通信的API,使用中每一个套接字都有一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入他所在的主机socket中,该socket通过与网络接口卡(NIC)相连的传输介质将这段信息送到另一台主机的socket中,使对方能够接收到这段信息。socket是由IP地址和端口结合的,提供应用层进程传送数据包的机制。

socket本意上“插座”的意思,在Linux环境中,用于表示进程间网络通信的特殊文件类型。本质上为内核借助缓冲区形成的伪文件。把它设置为文件,方便我们进行操作,我们可以通过文件描述符进行操作。与管道类型,Linux系统将期封装成文件的目的是为了统一接口,使得读写套接字和读写文件操作一样。区别是管道应用于本地进程间通信,而套接字多用于网络进程间数据的传递。

socket是全双工通信,即在同一时刻既可以数据读入,也可以数据输出。
【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

IP地址(逻辑地址): 在网络中唯一标识一台主机
端口号:在一台主机中唯一标识一个进程
IP+端口号:在网络环境中唯一标识一个进程

-服务器端:被动接受连接,一般不会主动发起连接

-客户端:主动向服务器发起连接

2、字节序

简介

现在CPU的累加器一次都能装载(至少)4个字节(32位机),即一个整数。那么这4个字节在内存中排列的顺序将影响它被累加器装载的整数值,这就是字节序问题。在各种计算机体系结构中,对于字节、字等的存储机制有所不同,因而引发了计算机通信领域中一个很重要的问题,即通信双方交流的信息单元应该以什么样的顺序进行传送。如果不达成一致的规则,通信双方将无法进行正确的编码/译码从而导致通信失败。

字节序,顾名思义宁节的顺序,就是大于一个宁节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)。

字节序分为大端字节序(Big-Endian)和小端字节序(Little-Endian)。大端字节序是指一个整数的高位字节存储在内存的低地址位置,低位字节存储在内存的高地址位置。小端字节序则是指一个整数的高位字节存储在内存高地址处,而低位字节则存储在内存的低地址处

【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

显然,一个数,越靠左边的是高位,越靠右边的是低位

下面,编写一个程序检测当前主机的字节序:
对联合体不了解的可以参考这篇文章——C语言 | 联合体详解

/*  
    字节序:字节在内存中存储的顺序。
    小端字节序:数据的高位字节存储在内存的高位地址,低位字节存储在内存的低位地址
    大端字节序:数据的低位字节存储在内存的高位地址,高位字节存储在内存的低位地址
*/

// 通过代码检测当前主机的字节序
#include <stdio.h>

int main() {

    union {
        short value;    // 2字节
        char bytes[sizeof(short)];  // char[2]
    } test; 

    test.value = 0x0102;
    if((test.bytes[0] == 1) && (test.bytes[1] == 2)) {
        printf("大端字节序\n");
    } else if((test.bytes[0] == 2) && (test.bytes[1] == 1)) {
        printf("小端字节序\n");
    } else {
        printf("未知\n");
    }

    return 0;
}

【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

字节序转换函数

当格式化的数据在两台使用不同字节序的主机之间直接传递时,接收端必然会错误的解释。解决问题的方法是:发送端总是把要发送的数据转换成大端字节序数据后再发送,而接收端知道对方传送过来的数据总是采用大端字节序,所以接收端可以根据自身采用的字节序决定是否对接收到的数据进行转换(小端机转换,大端机不转换)。

网络字节顺序是TCPIP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序采用大端排序方式。

BSD Socke t提供了封装好的转换接口,方便程序员使用。包括从主机字节序到网络字节序的转换函数: htons,htonl;从网络字节序到主机字节序的转换函数: ntohs、ntohl。

/*
h - host   主机,主机字节序

to   转换成什么

n - network   网络字节序

s - short unsigned short   端口

l - long unsigned int   IP

 网络通信时,需要将主机字节序转换成网络字节序(大端),
    另外一段获取到数据以后根据情况将网络字节序转换成主机字节序。

    // 转换端口
    uint16_t htons(uint16_t hostshort);		// 主机字节序 - 网络字节序
    uint16_t ntohs(uint16_t netshort);		// 网络字节序 - 主机字节序

    // 转IP
    uint32_t htonl(uint32_t hostlong);		// 主机字节序 - 网络字节序
    uint32_t ntohl(uint32_t netlong);		// 网络字节序 - 主机字节序
*/

#include <stdio.h>
#include <arpa/inet.h>

int main() {

    // htons 转换端口
    unsigned short a = 0x0102;
    printf("a : %x\n", a);
    unsigned short b = htons(a);
    printf("b : %x\n", b);

    printf("=======================\n");

    // htonl  转换IP
    char buf[4] = {192, 168, 1, 100};
    int num = *(int *)buf;
    printf("num : %d\n", num);
    
    int sum = htonl(num);
    unsigned char *p = (char *)&sum;

    printf("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3));

    printf("=======================\n");

    // ntohl
    unsigned char buf1[4] = {1, 1, 168, 192};
    int num1 = *(int *)buf1;
    int sum1 = ntohl(num1);
    unsigned char *p1 = (unsigned char *)&sum1;
    printf("%d %d %d %d\n", *p1, *(p1+1), *(p1+2), *(p1+3));
    
     // ntohs


    return 0;
}

【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

问题:打印num是1677830336是怎么回事呢?
答: // 192      168        1         100
  // 11000000 10101000 000000001 01101000
//本机是小端字节序,所以在192在低位,100在高位,所以num为
// 01101000  00000001  10101000  11000000 = 1677830336

3、socket地址

socket网络编程接口中表示socket地址是结构体sockaddr,其定义如下:

#include <bits/socket.h>

struct sockaddr{                                //已经被废弃掉

        sa_family_t sa_family;
        char sa_data[14];
};

typedef unsigned short int sa_family_t;

成员:
    sa_family成员是地址族类型(sa_family_t)的变量。地址族类型通常与协议类型对应。常见的协议族和对应的地址族如下所示:

协议族 地址族 描述
PF_UNIX AF_UNIX UNIX本地域协议族
PF_INET AF_INET TCP/IPv4协议族
PF_INET6 AF_INET6 TCP/IPv6协议族

协议族 PF_*和地址族AF_*都定义在头文件bits/socket.h中,二者值相同,可以混合使用(反正都是宏定义,宏定义是预处理阶段进行宏替换,所以混着用对编译运行不会有影响)

而sa_data成员用于存放socket地址值。但是,不同的协议族的地址值具有不同的含义和长度
【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)
可以看到,14个字节只能装下 IPv4地址,没办法装下IPv6的地址。因此,该结构体表示方式已经被废掉,Linux定义了下面这个新的通用的socket地址结构体,这个结构体不仅提供了足够大的空间用于存放地址值,而且是内存对齐的【内存对齐可以加快CPU访问速度】

这个结构体定义在:/usr/include/linux/in.h

#include <bits/socket.h>
struct sockaddr_storage
{
sa_family_t sa_family;
unsigned long int __ss_align; //不用管,用来作内存对齐的
char __ss_padding[ 128 - sizeof(__ss_align) ];
};
typedef unsigned short int sa_family_t;

专用socket地址

很多网络编程函数诞生早于IPv4协议(用自定义的协议咯,双方共同约定一个规则),那时候都是使用struck socketaddr结构体,*为了向前兼容,现在在socketaddr退化成了 (void )的作用,传递一个地址给函数,至于这个函数是sockaddr_in还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型

主要要记住的就是下图中的第二个struct sockaddr_in
【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)
UNIX 本地域协议族使用如下专用的 socket 地址结构体:

#include <sys/un.h>
struct sockaddr_un
{
sa_family_t sin_family;
char sun_path[108];
};

TCP/IP 协议族有 sockaddr_in 和 sockaddr_in6 两个专用的 socket 地址结构体,它们分别用于 IPv4 和 IPv6:

#include <netinet/in.h>
struct sockaddr_in
{
sa_family_t sin_family;         /* __SOCKADDR_COMMON(sin_) */
in_port_t sin_port;             /* Port number. 2个字节的端口号 */
struct in_addr sin_addr;        /* Internet address. 4个字节的ip地址 */

/* Pad to size of `struct sockaddr'.  剩余填充的部分*/
unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) - sizeof (struct in_addr)];
};


struct in_addr
{
in_addr_t s_addr;
};


struct sockaddr_in6
{
sa_family_t sin6_family;
in_port_t sin6_port; /* Transport layer port # */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* IPv6 scope-id */
};


typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))

所有专用 socket 地址(以及 sockaddr_storage)类型的变量在实际使用时都需要转化为通用 socket 地 址类型 sockaddr(强制转化即可),因为所有 socket 编程接口使用的地址参数类型都是 sockaddr

4、IP地址转换函数

人们习惯用可读性好的字符串来表示IP地址,比如用点分十进制字符串表示IPV4地址,以及用十六进制字符串表示IPv6地址,但编程中我们需要先把他们转化为整数(二进制)方能使用。而记录日志相反,我们需要把整数表示的IP地址转化为可读的字符串。

p:点分十进制的IP字符串

n:表示network,网络字节序的整数

#include  <arpa/inet.h>

将IP地址从字符串形式转化为二进制整数形式
int inet_pton(int af,const char *src,void *dst);

af:地址族: AF_INET AF_INET6

src:需要转换的点分十进制的IP字符串

dst:转换后的结果保存在这个里面

将网络字节序的整数,转换成点分十进制的IP地址字符串
const char *inet_ntop(int af,const void *src,char *dst,socklen_t size);

af:AF_INET   AF_INE6

src: 要转换的ip的整数的地址

dst: 转换成的IP地址字符串保存的地方

size:第三个参数的大小(数组的大小)

返回值:返回转换后的数据的地址(字符串),和 dst 是一样的

点分十进制 --->  网络字节序   inet_pton

网络字节序 --->  点分十进制   inet_ntop

代码举例:

/*
    #include <arpa/inet.h>
    // p:点分十进制的IP字符串,n:表示network,网络字节序的整数
    int inet_pton(int af, const char *src, void *dst);
        af:地址族: AF_INET  AF_INET6
        src:需要转换的点分十进制的IP字符串
        dst:转换后的结果保存在这个里面

    // 将网络字节序的整数,转换成点分十进制的IP地址字符串
    const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
        af:地址族: AF_INET  AF_INET6
        src: 要转换的ip的整数的地址
        dst: 转换成IP地址字符串保存的地方
        size:第三个参数的大小(数组的大小)
        返回值:返回转换后的数据的地址(字符串),和 dst 是一样的

*/

#include <stdio.h>
#include <arpa/inet.h>


int main() {

    // 创建一个ip字符串,点分十进制的IP地址字符串
    char buf[] = "192.168.1.4";
    unsigned int num = 0;

    // 将点分十进制的IP字符串转换成网络字节序的整数
    inet_pton(AF_INET, buf, &num);
    unsigned char * p = (unsigned char *)&num;
    printf("%d %d %d %d\n", *p, *(p+1), *(p+2), *(p+3));


    // 将网络字节序的IP整数转换成点分十进制的IP字符串
    char ip[16] = ""; //字符串IP地址四段,每段最多三个字节,加上3个“.”,再加一个字符串结束符
    const char * str =  inet_ntop(AF_INET, &num, ip, 16);
    printf("str : %s\n", str);
    printf("ip : %s\n", ip);
    printf("%d\n", ip == str);

    return 0;
}

【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)

5、套接字函数

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>//包含了这个头文件,上面两个就可以省略

int socket(int domain,int type,int protoco1);
	- 功能:创建一个套接字
	- 参数:
		- domain:协议族
			AF_INET:ipv4
			AF_INET6:ipv6
			AF_UNIX,AF_LOCAL:本地套接字通信(进程间通信)
		- type:通信过程中使用的协议类型
			SOCK_STREAM:流式协议(TCP等)
			SOCK_DGRAM:报式协议(UDP等)
		- protocol:具体的一个协议。一般写0
			- SOCK_STREAM:流式协议默认使用TCP
			- SOCK_DGRAM:报式协议默认使用UDP
		- 返回值:
			- 成功:返回文件描述符,操作的就是内核缓冲区
			- 失败:-1	
			
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
	- 功能:绑定,将fd和本地的IP+端口进行绑定
	- 参数:
			- socket:通过socket函数得到的文件描述符
			- addr:需要绑定的socket地址,这个地址封装了ip和端口号的信息
			- addr len:第二个参数结构体占的内存大小
			- 返回值:成功返回0,失败返回-1
			
int listen(int sockfd,int backlog);// /proc/sys/net/cor e/somaxconn
	- 功能:监听这个socket上的连接
	- 参数:
		- sockfd:通过socket()函数得到的文件描述符
		- backlog:未连接的和已连接的和的最大值,超过该设定的最大值的连接会被舍弃掉。但该设定值不能超过/proc/sys/net/cor e/somaxconn这个文件里的数值
		
int accept(int sockfd,struct sockaddr *addr ,sock1en_t *addrlen);
	- 功能:接收客户端连接,默认是一个阻塞的函数,阻塞等待客户的连接
	- 参数:
			- sockfd:用于监听的文件描述符
			- addr:传出参数,记录了连接成功后客户端的地址信息(IP和端口号)
			- addrlen:指定第二个参数的对应的内存的大小
	- 返回值:
			- 成功:返回用于通信的文件描述符
			- -1:失败
			
int connect(int sockfd,const struct sockaddr *addr,socklen_t addr1en);
	- 功能:客户端连接服务器
	- 参数:
			- sockfd:用于通信的文件描述符 
			- addr:客户端要连接的服务器的地址信息
			- addrlen:第二个参数的内存大小
	- 返回值:成功返回0,时报返回-1

ssize_t write(int fd,const void *buf, size_t count);
ssize_t read(int fd,void *buf, size_t count);

6、TCP通信实现(服务器端和客户端)

注意,该程序是根据TCP通信过程中服务器的接收信息的步骤写的,可以先参考该篇文章。

服务器端

// TCP 通信的服务器端

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main() {

    // 1.创建socket(用于监听的套接字)
    int lfd = socket(AF_INET, SOCK_STREAM, 0);

    if(lfd == -1) {
        perror("socket");
        exit(-1);
    }

    // 2.绑定
    struct sockaddr_in saddr;        //这个结构体本文章的上半部分有详细的介绍,不了解可以去看看
    saddr.sin_family = AF_INET;
    // inet_pton(AF_INET, "192.168.193.128", &saddr.sin_addr.s_addr);
    saddr.sin_addr.s_addr = INADDR_ANY;  // 0.0.0.0
    saddr.sin_port = htons(9999);
    int ret = bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));

    if(ret == -1) {
        perror("bind");
        exit(-1);
    }

    // 3.监听
    ret = listen(lfd, 8);
    if(ret == -1) {
        perror("listen");
        exit(-1);
    }

    // 4.接收客户端连接
    struct sockaddr_in clientaddr;
    int len = sizeof(clientaddr);
    int cfd = accept(lfd, (struct sockaddr *)&clientaddr, &len);
    
    if(cfd == -1) {
        perror("accept");
        exit(-1);
    }

    // 输出客户端的信息
    char clientIP[16];
    inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, clientIP, sizeof(clientIP));
    unsigned short clientPort = ntohs(clientaddr.sin_port);
    printf("client ip is %s, port is %d\n", clientIP, clientPort);

    // 5.通信
    char recvBuf[1024] = {0};
    while(1) {
        
        // 获取客户端的数据
        int num = read(cfd, recvBuf, sizeof(recvBuf));
        if(num == -1) {
            perror("read");
            exit(-1);
        } else if(num > 0) {
            printf("recv client data : %s\n", recvBuf);
        } else if(num == 0) {
            // 表示客户端断开连接
            printf("clinet closed...");
            break;
        }

        char * data = "hello,i am server";
        // 给客户端发送数据
        write(cfd, data, strlen(data));
    }
   
    // 关闭文件描述符
    close(cfd);
    close(lfd);

    return 0;
}

问题:假设服务端先调用一次read把客户端文件描述符中的内容读完了,这时候客户端没有往描述符中写数据了,但是也没有断开连接,那此时服务器第二次调用read会返回什么?
答:读管道的特点,当管道中无数据:1、写端被全部关闭,read返回0(相当于读到文件的末尾)2、写端没有完全关闭,read阻塞等待。参考我的这篇文章【Linux】管道的读写特点和管道设置为非阻塞

客户端

// TCP通信的客户端

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main() {

    // 1.创建套接字
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd == -1) {
        perror("socket");
        exit(-1);
    }

    // 2.连接服务器端,注意是要服务器的ip地址和端口
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    inet_pton(AF_INET, "192.168.177.146", &serveraddr.sin_addr.s_addr);
    serveraddr.sin_port = htons(9999);
    int ret = connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    if(ret == -1) {
        perror("connect");
        exit(-1);
    }

    
    // 3. 通信
    char recvBuf[1024] = {0};
    while(1) {

        char * data = "hello,i am client";
        // 给客户端发送数据
        write(fd, data , strlen(data));

        sleep(1);
        
        int len = read(fd, recvBuf, sizeof(recvBuf));
        if(len == -1) {
            perror("read");
            exit(-1);
        } else if(len > 0) {
            printf("recv server data : %s\n", recvBuf);
        } else if(len == 0) {
            // 表示服务器端断开连接
            printf("server closed...");
            break;
        }

    }

    // 关闭连接
    close(fd);

    return 0;
}

客户端第21行中的ip地址应该写自己主机的ip地址,我的主机的ip地址为192.168.177.146

分别将两个文件编译并执行。得到结果如下:
【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)
【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)
可以看到,在服务器的执行程序中,打印出了客户端的ip为192.168.177.146,端口随机分配为35302

注意:要先启动服务端,再启动客户端。

作业:把服务器改为回频服务器,也就是服务器把客户端发送来的数据再发送回去。把客户端改为从键盘输入数据并发送给服务端。所以最后的效果就是,我从键盘输入,客户端发送给服务端,服务端再把相同的内容发送回来。

服务端:

// TCP 通信的服务器端

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main() {

    // 1.创建socket(用于监听的套接字)
    int lfd = socket(AF_INET, SOCK_STREAM, 0);

    if(lfd == -1) {
        perror("socket");
        exit(-1);
    }

    // 2.绑定
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    // inet_pton(AF_INET, "192.168.193.128", &saddr.sin_addr.s_addr);
    saddr.sin_addr.s_addr = INADDR_ANY;  // 0.0.0.0
    saddr.sin_port = htons(9999);
    int ret = bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));

    if(ret == -1) {
        perror("bind");
        exit(-1);
    }

    // 3.监听
    ret = listen(lfd, 8);
    if(ret == -1) {
        perror("listen");
        exit(-1);
    }

    // 4.接收客户端连接
    struct sockaddr_in clientaddr;
    int len = sizeof(clientaddr);
    int cfd = accept(lfd, (struct sockaddr *)&clientaddr, &len);
    
    if(cfd == -1) {
        perror("accept");
        exit(-1);
    }

    // 输出客户端的信息
    char clientIP[16];
    inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, clientIP, sizeof(clientIP));
    unsigned short clientPort = ntohs(clientaddr.sin_port);
    printf("client ip is %s, port is %d\n", clientIP, clientPort);

    // 5.通信
    char recvBuf[1024] = {0};
    while(1) {
        memset(recvBuf, 0, 1024);
        // 获取客户端的数据
        int num = read(cfd, recvBuf, sizeof(recvBuf));
        if(num == -1) {
            perror("read");
            exit(-1);
        } else if(num > 0) {
            printf("recv client data : %s\n", recvBuf);
        } else if(num == 0) {
            // 表示客户端断开连接
            printf("clinet closed...");
            break;
        }

        char * data = recvBuf;;
        // 给客户端发送数据
        write(cfd, data, strlen(data));
    }
   
    // 关闭文件描述符
    close(cfd);
    close(lfd);

    return 0;
}

客户端:

// TCP通信的客户端

#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main() {

    // 1.创建套接字
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd == -1) {
        perror("socket");
        exit(-1);
    }

    // 2.连接服务器端,注意是要服务器的ip地址和端口
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    inet_pton(AF_INET, "192.168.177.146", &serveraddr.sin_addr.s_addr);
    serveraddr.sin_port = htons(9999);
    int ret = connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    if(ret == -1) {
        perror("connect");
        exit(-1);
    }

    
    // 3. 通信
    char recvBuf[1024] = {0};
    while(1) {

        char data[1024];
        memset(data, 0, 1024);
        printf("请输入发送数据:\n");
        scanf("%s", data);
        // 给客户端发送数据
        write(fd, data , strlen(data));

        sleep(1);
        
        memset(recvBuf, 0, 1024);
        int len = read(fd, recvBuf, sizeof(recvBuf));
        if(len == -1) {
            perror("read");
            exit(-1);
        } else if(len > 0) {
            printf("recv server data : %s\n", recvBuf);
        } else if(len == 0) {
            // 表示服务器端断开连接
            printf("server closed...");
            break;
        }

    }

    // 关闭连接
    close(fd);

    return 0;
}

【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)
【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)文章来源地址https://www.toymoban.com/news/detail-492778.html

到了这里,关于【Linux】socket 编程(socket套接字介绍、字节序、socket地址、IP地址转换函数、套接字函数、TCP通信实现)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • socket | 网络套接字、网络字节序、sockaddr结构

    欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。 专栏:《网络编程》 Socket本身有“插座”的意思

    2024年02月05日
    浏览(36)
  • Linux网络编程:Socket套接字编程(Server服务器 Client客户端)

    文章目录: 一:定义和流程分析 1.定义 2.流程分析  3.网络字节序 二:相关函数  IP地址转换函数inet_pton inet_ntop(本地字节序 网络字节序) socket函数(创建一个套接字) bind函数(给socket绑定一个服务器地址结构(IP+port)) listen函数(设置最大连接数或者说能同时进行三次握手的最

    2024年02月12日
    浏览(79)
  • 【Linux网络】网络编程套接字 -- 基于socket实现一个简单UDP网络程序

    我们把数据从A主机发送到B主机,是目的吗?不是,真正通信的不是这两个机器!其实是这两台机器上面的软件(人) 数据有 IP(公网) 标识一台唯一的主机 ,用谁来标识各自主机上客户或者服务进程的唯一性呢? 为了更好的表示一台主机上服务进程的唯一性,我们采用 端口号

    2024年02月12日
    浏览(130)
  • Linux下基于TCP协议的Socket套接字编程(客户端&服务端)入门详解

    写在前面: 本篇博客探讨实践环境如下: 1.操作系统: Linux 2.版本(可以通过命令 cat /etc/os-release 查看版本信息):PRETTY_NAME=“CentOS Linux 7 (Core)” 编程语言:C 常常说socket 、套接字 那么socket 到底指的是什么? socket 本质上是一个抽象的概念,它是一组用于 网络通信的 API , 提供

    2024年02月01日
    浏览(53)
  • 【Python】Python 网络编程 ( Socket 套接字简介 | Socket 套接字使用步骤 | Socket 套接字服务端与客户端开发 )

    Socket 套接字 是一种 进程之间的 通信机制 , 通过套接字可以在 不同的进程之间 进行数据交换 ; 在 网络编程 中 , Socket 套接字 主要用于 客户端 与 服务器 之间的 通信 , 大部分 网络相关的应用程序 , 都使用到了 Socket 套接字技术 ; 套接字有两种类型 : 流套接字 : 提供了一个可

    2024年02月15日
    浏览(130)
  • 「网络编程」第二讲:socket套接字(四 - 完结)_ Linux任务管理与守护进程 | TCP协议通讯流程

    「前言」文章是关于网络编程的socket套接字方面的,上一篇是网络编程socket套接字(三),这篇续上篇文章的内容,下面开始讲解!  「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「句子分享」 Time goes on and on, never to an 

    2024年02月10日
    浏览(60)
  • 网络编程套接字(Socket)

    认识IP地址, 端口号, 网络字节序等网络编程中的基本概念; 学习socket api的基本用法; 能够实现一个简单的udp客户端/服务器; 能够实现一个简单的tcp客户端/服务器(单连接版本, 多进程版本, 多线程版本); 理解tcp服务器建立连接, 发送数据, 断开连接的流程; 通俗易懂地说,源

    2024年01月21日
    浏览(53)
  • 【网络编程】socket套接字

    如果我们的台式机或者笔记本没有IP地址就无法上网,而因为每台主机都有IP地址,所以注定了数据从一台主机传输到另一台主机 一定有源IP和目的IP 。 所以在报头中就会包含源IP和目的IP。 而我们把数据从一台主机传递到另一台主机并不是目的,真正通信的其实是应用层上的

    2024年02月02日
    浏览(61)
  • 14.1 Socket 套接字编程入门

    Winsock是Windows操作系统上的套接字API,用于在网络上进行数据通信。套接字通信是一种允许应用程序在计算机网络上进行实时数据交换的技术。通过使用Windows提供的API,应用程序可以创建一个套接字来进行数据通信。这个套接字可以绑定到一个端口,以允许其他应用程序连接

    2024年02月08日
    浏览(44)
  • 网络编程—Socket套接字详解

    目录 一、网络编程 1.1、为什么需要网络编程? 1.2、什么是网络编程 1.3、发送端和接收端 ​编辑1.4、请求和响应 ​编辑1.5、客户端和服务端  二、Socket套接字  2.1、概念 2.2、分类  2.2.1、流套接字  2.2.2、数据报套接字  2.2.3、原始套接字  2.3、Socket编程注意事项  1.1、为什

    2024年02月16日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包