Socket 通信

news/2024/11/14 15:41:45/

文章目录

    • Socket 通信创建流程图
    • 通信示例
    • 对一些概念进行讲述
    • 对Socke 编程所用的函数进行讲解

网络通信 和 Socket

Socket 通信流程图 :

通信示例 

对Socket 编程有一个初步的了解, 看看具体代码是如何实现的. 

示例的主要功能:  实现大小写的转化,客户端发送数据

服务器端进行处理,再返回给客户端.

服务器端的实现   echo_socket.c

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<ctype.h>
#include<arpa/inet.h>#define SERVER_PORT  666     //服务器的端口号int main(void){int sock;//代表信箱struct sockaddr_in server_addr; //标签,保存端口号,ip地址等//1, 创建信箱sock = socket( AF_INET , SOCK_STREAM , 0);//2. 清空标签,写上地址和端口号bzero( &server_addr ,sizeof(server_addr));server_addr.sin_family = AF_INET; //选择协议族IPV4server_addr.sin_addr.s_addr = htonl( INADDR_ANY ); //监听本地所有ip地址server_addr.sin_port = htons( SERVER_PORT ); //绑定我们的端口号//3. 将我们的标签贴到信箱上bind(sock ,(struct sockaddr *)&server_addr,sizeof(server_addr));//4. 将我们的信箱挂到传达室,这样,保安就可以接收信件了listen(sock, 128);    //这里的128表示同时可以接收的信件数量//万事俱备,只等来信printf("等待客户端的来信\n");int done =1;//不断接受来信while( done ){struct sockaddr_in client;int client_sock,len;char client_ip[64];char buff[256];socklen_t client_addr_len;client_addr_len = sizeof(client);client_sock = accept(sock ,(struct sockaddr *)&client, &client_addr_len);//打印客户端ip地址和端口号//inet_ntop  将网络字节序转化成字符串printf("client ip: %s\t port : %d\n",inet_ntop( AF_INET, &client.sin_addr.s_addr,client_ip,sizeof(client_ip)), ntohs(client.sin_port));//5 、读取客户端发送的数据   read()len=read(client_sock , buff , sizeof(buff)-1);//手动添加字符串结束符buff[len]='\0';//打印读取的信息printf("recive :%s recive len :%d \n",buff,len);/* 完成大小写转换 */int i=0;for(i ; i< len ;i++){if(buff[i]>='a' && buff[i] <= 'z'){    //小写字母buff[i]-=32;}else if(buff[i]>='A' && buff[i] <= 'Z'){buff[i]+=32;}// buff[i]=toupper(buff[i]);}//6. 将读取到的信息写回去len = write( client_sock, buff, len ) ;printf("write finaled  :%s  len: %d\n", buff, len );//7. 关闭客户端close( client_sock );	}return 0;
}

客户端的实现  echo.client.c 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
//#include<netinet/in.h>
#include <arpa/inet.h>#define SERVER_PORT 666
#define SERVER_IP "127.0.0.1"    //本地环回地址int main(int argc , char *agrv[]){int sockfd;     //定义一个邮箱char *message; struct sockaddr_in serveraddr;    //定义标签,包括端口号和ip//清空标签memset( &serveraddr ,0 ,sizeof(serveraddr));if( argc!=2 ){fputs("usage : echo_client message \n",stderr);exit(1);}message = agrv[1];printf("message : %s\n",message);//创建信箱sockfd = socket ( AF_INET ,SOCK_STREAM , 0 );//写上端口号和ipserveraddr.sin_family = AF_INET ;  //网络簇inet_pton( AF_INET ,SERVER_IP ,&serveraddr.sin_addr);serveraddr.sin_port= htons(SERVER_PORT);       //写上端口号//连接信箱connect( sockfd ,(struct sockaddr *)&serveraddr, sizeof(serveraddr)); //写数据int len;char buff[64];write( sockfd ,message , sizeof(message)-1);len = read (sockfd , buff , sizeof(buff)-1);if(len >0 ){buff[len]='\0';printf("recive :%s\n",buff);}else{printf("error\n");}printf("finished. \n");close(sockfd);return 0;
}

结果显示:

概念讲述 :

  • 套接字
  • 网络字节序
  • sockaddr 数据结构
  • ip地址转换函数

套接字(socket):

表示进程在网络上的一个连接点。每个套接字都有一个唯一的端口号和IP地址,用于标识该套接字所连接的远程主机和端口, 欲建立连接的两个进程各自有应该socket 来标识, 那么这两个socket 就组成一个 socke pari 就唯一标识一个连接。

网络字节序:

计算机中有两种字节序

大端字节序   - > 低地址高字节, 高地址低字节

小端字节序   - > 低地址低字节, 高地址高字节

内存中的多字节数据相对于内存地址有大端和小端之分 , 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。

网络数据流同样有大端小端之分。

发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。

 如何实现网络网络字节序和主机字节序的转换。

//包含头文件

#include <arpa/inet.h>

uint32_t htonl ( uint32_t  hostlong ) ;

uint16_t htons ( uint16_t  hostlong) ;

uint32_t ntopl ( uint32_t  hostlong ) ;

uint16_t  ntohs ( uint16_t  hostlong ) ;

/*

1、h  - >  host  (主机)

2、n  - >  network ( 网络 )

3 、l   - >  32位长整型

4、 s  - >  16位短整形 

5、to  - > 转换的意思可以理解成

*/

sockaddr 数据结构:

内部结构:

struct sockeaddr{sa_family_t  sa_family ;    //网络地址族, 如ipv4 (AF_INET)char sa_data[14];           //14字节的地址数据
}struct sockeaddr_in{sa_family_t   sin_family;in_port_t   sin_port;       //端口号struct  in_addr_sin_addr;   //网络地址 
}struct  in_addr_sin_addr{uint32_t  s_addr;          //网络字节序地址
}

ip地址转换函数:

//头文件

#include <arpa/inet.h>

// //网络协议地址(如IPv4或IPv6地址)转换为二进制格式

int inet_pton ( int  af , const char  * , char  *src , void *dst ) ;     

//将一个二进制格式的网络协议地址(如IPv4或IPv6地址)转换为字符串形式

const char * inet_ntop ( int af ,const void  *src ,char *dst ,socklen_t   size );

Socket 编程函数

socket() 函数  :

打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,这里就是相当于创建一个套接字 , 如果失败则返回  -1 。

#include < sys/types.h >       // 需要的头文件

#include < sys/socket.h >

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

// 参数说明

domain  :   地址族

这个参数用于指定套接字所使用的地址族(Address Family),它决定了套接字通信所使用的协议和网络地址的类型。

常用的地址族有AF_INET(IPv4网络)、AF_INET6(IPv6网络)等。在大多数情况下,我们使用AF_INET来创建套接字。  

type  :    套接字类型

这个参数用于指定套接字的类型,即数据传输的方式。常用的套接字类型有SOCK_STREAM(流套接字)和SOCK_DGRAM(数据报套接字)。

SOCK_STREAM 表示可靠的、面向连接的通信,通常使用TCP协议;而SOCK_DGRAM表示不可靠的、无连接的通信,通常使用UDP协议。根据实际需求选择合适的套接字类型。

protocol   :     协议      ( 默认0 ,一般情况不需要我们填写 )

这个参数用于指定套接字所使用的具体协议。

一般情况下,我们可以将这个参数设置为0,表示使用默认协议。

对于SOCK_STREAM类型的套接字,默认协议是TCP;对于SOCK_DGRAM类型的套接字,默认协议是UDP。如果需要使用其他特定的协议,可以根据协议类型设置这个参数。

bind( )   函数

将套接字绑定到指定的地址和端口。

#include < sys/types.h >

#include < sys/socket.h >

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

//  参数说明

sockfd   :   套接字 ,  由socket()函数返回的套接字描述符。

addr  :    指向套接字地址结构的指针,它包含了要绑定的IP地址和端口号。

               对于IPv4,这个地址结构通常是struct sockaddr_in类型。

  

addrlen  :   地址结构的长度    sizeof()  求出 

bind()  方法会在指定的地址和端口上绑定套接字。

如果绑定成功,返回0;如果绑定失败,返回-1,并设置相应的错误码。

  • 在调用bind()方法之前,必须确保已经使用socket()函数成功创建了套接字。
  • 绑定的IP地址和端口号应该有效且可用,避免和其他进程冲突。
  • 如果绑定的地址和端口已经被占用,将会导致绑定失败。

listen( )  函数 : 

用于将套接字转换为被动套接字,使其能够接受其他主机的连接请求。

它通常用于服务器端,使服务器能够监听并接受客户端的连接。

#include < sys/types .h >

#include < sys/socket.h >

int  listen ( int  sockfd  , int  backlog )  ;

//  参数说明 

sockfd   :     套接字

backlog  :  这个参数指定了同时等待处理的连接请求的最大数量。

                  当多个客户端同时向服务器发起连接请求时,如果连接请求的数量超过了                                backlog 指定的值,多余的连接请求可能会被拒绝。   

如果listen()函数调用成功,返回0;如果调用失败,返回-1。

使用listen()函数后,服务器就进入了“监听”状态,等待客户端的连接请求。

accept (  )  函数  :

用于接受从客户端发起的连接请求。

一旦有连接请求到达,accept() 函数会创建一个新的套接字,用于与客户端进行通信,并返回这个新套接字的描述符。

#include < sys/types.h >

#include < sys/socket.h >

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

// 参数说明

sockefd   :   套接字

addr   :      指向套接字地址结构的指针,它包含了要绑定的IP地址和端口号。

                 对于IPv4,这个地址结构通常是struct sockaddr_in类型。

                 如果不关心客户端的地址信息,这个参数可以设置为NULL

addrlen  :  这是一个指向socklen_t类型的指针,用于存储addr结构体的长度。

  

如果连接成功建立,则返回新创建的套接字的描述符。

如果发生错误,则返回-1,并设置相应的错误码。

connect  (  )  函数  : 

客户端向服务器发起连接请求。

#include < sys/types.h >

#include < sys/socket .h >

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

// 参数说明

sockfd  :   套接字

addr    :     指向套接字地址结构的指针,它包含了要绑定的IP地址和端口号。

addrlen  :   这是一个指向socklen_t类型的指针,用于存储addr结构体的长度。

当调用connect()函数时,它会尝试与指定的服务器建立连接。

如果连接成功建立,函数返回0;

如果连接失败,返回-1,并设置相应的错误码。

出错处理函数 : 

perror ( )函数 :

用于输出上一个系统调用失败时的错误描述信息。

#include < stdio.h >

#include < errno.h >

void  perror ( const  char  *s)  ;

// 例如

perror ( " connect failed " );  

法二  :  使用 fprintf ()  

它通常用于输出程序运行过程中的错误信息。与stdout(标准输出)不同,stderr的输出通常会被送到终端窗口。

fprintf( stderr, "error message :%s \n", strerror(errno) )// strerror ()   获取错误描述


http://www.ppmy.cn/news/1202380.html

相关文章

OSS 是什么

OSS 在不同的上下文中有不同的含义&#xff0c;但在云计算领域&#xff0c;OSS 通常指的是“对象存储服务”(Object Storage Service)。特别是在阿里云&#xff08;Alibaba Cloud&#xff09;这个环境中&#xff0c;OSS 是指阿里云提供的对象存储服务。 对象存储服务是一种存储…

Kibana Dashboard饼图展示keyword子字符串去重统计

日志内容 log.info("请求开始 uri: {} header RequestId:{}", request.getRequestURI(), reqId, request.getHeader("request_id"));操作步骤 进入Dashboard菜单 点击Create Dashboard按钮 点击Create Panel按钮 选择Aggregation based 然后选择Pie饼图 …

Day 53 单调栈 part03

Day 53 单调栈 part03 解题理解 1道题目 84. 柱状图中最大的矩形 解题理解 本题是要找每个柱子左右两边第一个小于该柱子的柱子&#xff0c;所以从栈头&#xff08;元素从栈头弹出&#xff09;到栈底的顺序应该是从大到小的顺序&#xff01; 只有栈里从大到小的顺序&#xf…

蓝桥杯算法竞赛系列第九章·巧解哈希题,用这3种数据类型足矣

你好&#xff0c;我是安然无虞。 文章目录 哈希基础概念哈希相关题目 有效的字母异位词 赎金信 字母异位词分组 两个数组的交集 快乐数 两数之和 四数相加 II 最长连续序列 查找共用字符 同构字符串 单词规律 字节跳动面试&#xff1a;缺失的第一个正数 哈喽哈喽&#xff0c;好…

Nginx 实现负载均衡

目录 一&#xff1a;负载均衡介绍 二、 负载均衡具备的功能 1.提高服务器性能 2.提高系统可用性 3.提高系统的可伸缩性 4.实现流量均衡 三、示例配置&#xff0c;如何使用nginx实现负载均衡 四、负载均衡策略配置 1.基于轮询的负载均衡&#xff08;默认&#…

Python接口自动化测试post请求和get请求,获取请求返回值

引言 我们在做python接口自动化测试时&#xff0c;接口的请求方法有get,post等&#xff1b;get和post请求传参&#xff0c;和获取接口响应数据的方法&#xff1b; 请求接口为Post时&#xff0c;传参方法 我们在使用python中requests库做接口测试时&#xff0c;在做post接口测试…

tcpreplay命令后加上“--maxsleep=num“,num表示最大延迟时间(单位毫秒)

这个参数的含义是控制在发送每个数据包之间的最大延迟时间&#xff0c;单位是毫秒。它可以用来模拟真实网络中的一些延迟情况&#xff0c;比如网络拥塞、带宽限制等。 使用方法是在tcpreplay命令后加上"--maxsleepnum"&#xff0c;num表示最大延迟时间&#xff0c;例…

jenkins gitlab CI/CD

jenkins的安装教程就不说了&#xff1a;Jenkins docker 一键发布 (一)_jenkins 一键发布-CSDN博客 最近打算从svn切换到gitlab&#xff0c;所以配置了一下jenkins的git 很简单&#xff0c;直接上图 1 选择 Git 2 录入gitlab的http地址&#xff08;由于我的git地址不是22端口&…