Linux网络编程:Socket套接字编程(Server服务器 Client客户端)

这篇具有很好参考价值的文章主要介绍了Linux网络编程:Socket套接字编程(Server服务器 Client客户端)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章目录:

一:定义和流程分析

1.定义

2.流程分析 

3.网络字节序

二:相关函数 

IP地址转换函数inet_pton inet_ntop(本地字节序 网络字节序)

socket函数(创建一个套接字)

bind函数(给socket绑定一个服务器地址结构(IP+port))

listen函数(设置最大连接数或者说能同时进行三次握手的最大连接数监听上限)

accept函数(阻塞监听等待客户端建立连接, 成功的话返回一个与客户端成功连接的socket文件描述符)

connect函数(使用现有的socket与服务器建立连接)

三:服务器模型和客户端模型的实现 

Server服务器的实现

Client客户端的实现


一:定义和流程分析

1.定义

定义:一个文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现)
         在通信过程中, 套接字一定是成对出现的
        一种文件类型,伪文件,不占用存储空间,可进行IO操作,可间接看做文件描述符使
        Socket本身有“插座”的意思
        在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件

    管道, 套接字, 块设备, 字符设备;
    套接字: 一个fd可以索引读写两个缓冲区;



套接字的作用
    套接字是网络通信中的一种端点,它提供了应用层进程利用网络协议交换数据的机制
    套接字可以用于不同主机上的应用进程之间进行双向通信,使得它们可以交换数据、同步连接状态、处理错误等

    在计算机系统中,套接字通常被实现为文件描述符,用于在网络上进行数据传输
    当应用程序打开一个套接字时,操作系统会为它分配一个唯一的文件描述符,以便于进程间通信

2.流程分析 

Linux网络编程:Socket套接字编程(Server服务器 Client客户端),# Linux网络编程,linux,运维,服务器

 Linux网络编程:Socket套接字编程(Server服务器 Client客户端),# Linux网络编程,linux,运维,服务器

socket():创建一个套接字, 用fd索引

bind():绑定IP和port

listen():设置监听上限(同时与Server建立连接数)

accpet():阻塞监听客户端连接(传入一个上面创建的套接字, 传出一个连接的套接字)

在客户端中的connect()中绑定IP和port,并建立连接(阻塞)

3.网络字节序

小端法:(pc本地存储)	高位存高地址。低位存低地址。	int a = 0x12345678
大端法:(网络存储)	高位存低地址。低位存高地址。

htonl --> 本地--》 网络 (IP)			192.168.1.11 --> string --> atoi --> int --> htonl --> 网络字节序
htons --> 本地--》 网络 (port)
ntohl --> 网络--》 本地(IP)
ntohs --> 网络--》 本地(Port)

用库函数做网络字节序和主机字节序的转换

#include<arpa/inet.h>
uint32_t htonl(uint32_t hostlong);			//主要针对IP
uint16_t htons(uint16_t hostshort);			//主要针对port
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

二:相关函数 

IP地址转换函数inet_pton inet_ntop(本地字节序 网络字节序)

由于如192.168.45.2这种的IP地址为点分十进制表示,需要转化为uint32_t型,有现成的函数(IPv4和IPv6都可以转换) 

//本地字节序(string IP) ---> 网络字节序
int inet_pton(int af, const char *src, void *dst);		                   
	af:AF_INET、AF_INET6
	src:传入,IP地址(点分十进制)
	dst:传出,转换后的 网络字节序的 IP地址。 
	返回值:
		成功: 1
		异常: 0, 说明src指向的不是一个有效的ip地址。
		失败:-1


//网络字节序 ---> 本地字节序(string IP)
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);	
	af:AF_INET、AF_INET6
	src: 网络字节序IP地址
	dst:本地字节序(string IP)
	size: dst 的大小。
	返回值: 成功:dst、失败:NULL

socket函数(创建一个套接字)

#include <sys/socket.h>


int socket(int domain, int type, int protocol);		创建一个 套接字

    domain指定使用的协议(IPv4或IPv6)
	    AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址
	    AF_INET6 与上面类似,不过是来用IPv6的地址
	    AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用

    type指定数据传输协议(流式或报式)
        SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
	    SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
	    SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
	    SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
	    SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序

    指定代表协议(一般默认传0)protocol: 0 
        流式以TCP为代表;
        报式以UDP为代表;

    返回值:返回指向新创建的socket的文件描述符
        成功:返回新套接字所对应文件描述符fd
        失败:返回-1并设置errno;

bind函数(给socket绑定一个服务器地址结构(IP+port))

#include <sys/socket.h>


 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);		给socket绑定一个 地址结构 (IP+port)

	sockfd: socket文件描述符
		struct sockaddr_in servaddr;
		addr.sin_family = AF_INET;
		addr.sin_port = htons(8888);
		addr.sin_addr.s_addr = htonl(INADDR_ANY);

    addr: 构造出IP地址加端口号
        传入参数(struct sockaddr *)&addr

    addrlen: sizeof(addr) 地址结构的大小


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

listen函数(设置最大连接数或者说能同时进行三次握手的最大连接数监听上限)

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


int listen(int sockfd, int backlog);        //设置同时与服务器建立连接的上限数(同时进行3次握手的客户端数量)

    sockfd:
        socket文件描述符

    backlog:上限数值。最大值 128
	    排队建立3次握手队列和刚刚建立3次握手队列的链接数和

    返回值:
		成功:0
		失败:-1 errno	

accept函数(阻塞监听等待客户端建立连接, 成功的话返回一个与客户端成功连接的socket文件描述符)

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


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

    sockfd:
	    socket文件描述符

    addr:成功与Sever建立连接的那个**客户端**的地址结构;
	    传出参数,返回链接客户端地址信息(IP地址+端口号)

    addrlen:传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小	    
​	    socklen_t clit_addr_len=sizeof(addr);
​	    入: 传入addr的大小;
​	    出: 客户端addr的实际大小;

    返回值:    
​	    成功: 返回能与客户端进行通信的socket对应的文件描述符;
​	    失败: 返回-1并设置errno;



//我们的服务器程序结构是这样的
while (1) {
	cliaddr_len = sizeof(cliaddr);
	connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
	n = read(connfd, buf, MAXLINE);
	......
	close(connfd);
}

connect函数(使用现有的socket与服务器建立连接)

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


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

    sockdf:socket文件描述符
    	struct sockaddr_in srv_addr;		// 服务器地址结构
		srv_addr.sin_family = AF_INET;
		srv_addr.sin_port = 9527 	跟服务器bind时设定的 port 完全一致。
		inet_pton(AF_INET, "服务器的IP地址",&srv_adrr.sin_addr.s_addr);
	    

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

    addrlen:
	    传入参数,服务器地址结构的长度sizeof(addr)大小

    返回值:
	   ​	成功返回0;
​	    失败返回-1并设置errno;


如果不使用`bind()`函数绑定客户端的地址结构, 会采用**"隐式绑定"**;

三:服务器模型和客户端模型的实现 

Server服务器的实现

server:
	1. socket()	创建socket

	2. bind()	绑定服务器地址结构

	3. listen()	设置监听上限

	4. accept()	阻塞监听客户端连接

	5. read(fd)	读socket获取客户端数据

	6. 小--大写	toupper()

	7. write(fd)

	8. close();

代码逻辑

#include <stdio.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
 
#define SERV_PORT 9527					//端口号
 
int main(int argc, char *argv[]){
    int link_fd=0;						//建立连接的socket文件描述符
    int connect_fd=0					//用于通信的文件描述符
    int ret=0;							//用于检查是否出错
    char buf[BUFSIZ];					//缓冲区
    char client_IP[1024]				//存入客户端IP字符串
    int num=0;							//读出的字节数
    /*服务器端地址结构*/
    struct sockaddr_in serv_addr;                   	 // 定义服务器地址结构 和 客户端地址结构
		serv_addr.sin_family=AF_INET;                    // IPv4
		serv_addr.sin_port=htons(SERV_PORT);             // 转为网络字节序的 端口号
		serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);     // 获取本机任意有效IP
    
    /*成功与服务器建立连接的客户端地址结构*/
    struct sockaddr_in clint_addr;
    socklen_t clint_addr_len=sizeof(clint_addr);    	 // 获取客户端地址结构大小
        
 
 
 
    /*1.socket函数:创建用于建立连接的socket,返回的文件描述符存入link_fd*/
		//IPv4,按照顺序基于字节流的连接,指定代表协议
		link_fd=socket(AF_INET,SOCK_STREAM,0);		
		if(link_fd==-1)
			sys_err("socket error");
    
    /*2.bind函数:绑定服务器端的socket绑定地址结构(IP+port)*/
		//socket文件描述符link_fd,IP地址加端口号
		ret=bind(link_fd,(const struct sockaddr*)&serv_addr,sizeof(serv_addr));
		if(ret==-1)
			sys_err("bind error");
    
    /*3.listen函数:设定监听(连接)上线*/
    ret=listen(link_fd,128); 
    if(ret==-1)
        sys_err("listen error");
    
    /*4.accept函数:阻塞等待客户端建立连接*/
		//文件描述符,与Sever建立连接的客户端的地址结构,返回真正接收到地址结构体的大小
		connect_fd=accept(link_fd,(	struct sockaddr*)&clint_addr,&clint_addr_len);    
		if(connect_fd==-1)
			sys_err("accept error");
 
    /*建立连接后打印客户端的IP和端口号    获取客户端地址结构*/
        printf(
				"client IP:%s,client port:%d",  												//`client_IP`是前面定义的客户端IP字符串的缓冲区, 大小为1024           
				inet_ntop(AF_INET,&clint_addr.sin_addr.s_addr,client_IP,sizeof(client_IP)),		//网络字节序 ---> 本地字节序
				ntohs(clint_addr.sin_port)														//根据accept传出参数,获取客户端 ip 和 port
			  );           
    
    /*业务逻辑*/
    while(1){
        //5. read(fd)	读socket获取客户端数据
			num=read(connect_fd,buf,sizeof(buf));    // 读客户端数据
			write(STDOUT_FILENO,buf,num);            // 写到屏幕查看
 
        //6. 小--大写	toupper()
			for(i=0;i<num;i++)                       // 小写 -- 大写
				buf[i]=toupper(buf[i]);
 
        //7. write(fd)
			write(connect_fd,buf,num);               // 将大写,写回给客户端
 
        sleep(1);
    }
 
    
    //8. close()
		close(connect_fd);
		close(link_fd);
 
  
   	return 0;
}

测试命令 

`nc 127.0.0.1 9527`        //脑残命令: 向这个服务发送信息并打印回执

Client客户端的实现

client:
	1. socket()	创建socket

	2. connect();	与服务器建立连接

	3. write()	写数据到 socket

	4. read()	读转换后的数据

	5. 显示读取结果

	6. close()

代码逻辑文章来源地址https://www.toymoban.com/news/detail-660680.html

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
 
#define SERV_PORT 9527
 
/*错误处理函数*/
void sys_err(const char* str){
	perror(str);
	exit(1);
}
 
int main(int argc, char *argv[])){
	int client_fd=0;
	int ret=0;
	int num=0;
	int cnt=10;
	char buf[BUFSIZ];
 
	//connect的参数2填入服务器的文件描述符!
	struct sockaddr_in serv_addr;
		serv_addr.sin_family=AF_INET;
		serv_addr.sin_port=htons(SERV_PORT);
    

	// 本地字节序(string IP) ---> 网络字节序
	inet_pton(AF_INET,"127.0.0.1",(void*)&serv_addr.sin_addr.s_addr);
 
 
 
    /*1. 创建socket():客户端直接创建用于连接的套接字即可*/
		client_fd=socket(AF_INET,SOCK_STREAM,0);
		if(client_fd==-1)
			sys_err("socket error");
 
    /*2. connect():将客户端套接字与服务器地址结构连接起来*/
		ret=connect(client_fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
		if(ret!=0)
			sys_err("connect error");
    
	//业务逻辑
	while(--cnt){
		
        //3. write()	写数据到 socket
			write(client_fd,"fuckyou\n",8);
		
        //4. read()	读转换后的数据。
			num=read(client_fd,buf,sizeof(buf));
 
        //5. 显示读取结果
			write(STDOUT_FILENO,buf,num);

		sleep(1);
	}
 
    //6. close()
		close(client_fd);
 
	return 0;
}

到了这里,关于Linux网络编程:Socket套接字编程(Server服务器 Client客户端)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【网络编程】socket套接字

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

    2024年02月02日
    浏览(43)
  • 【网络编程】网络编程 和 Socket 套接字认识

    ✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 用户在浏览器中,打开在线视频网站,如优酷看视频,实质是通过网络,获取到网络上的一个视频资源。 与本地打开视频文件类似,只是视频文件这个资源的来源是网络。 相比本地资源来说,网络提供了更为丰富的网络资源:

    2023年04月15日
    浏览(38)
  • 网络编程—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日
    浏览(33)
  • 「网络编程」第二讲:网络编程socket套接字(一)

    「前言」文章是关于网络编程的socket套接字方面的,下面开始讲解! 「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「每篇一句」 春风得意马蹄疾,一日看尽长安花。 ——孟郊《登科后》 目录 一、预备知识 1.1 源IP和目的IP 1.

    2024年02月09日
    浏览(39)
  • [JAVAee]网络编程-套接字Socket

    目录 基本概念 发送端与接收端 请求与响应 ​编辑客户端与服务器 Socket套接字  分类 数据报套接字 流套接字传输模型   UDP数据报套接字编程 DatagramSocket API DatagramPacket API InetSocketAddress API 示例一: 示例二: TCP流数据报套接字编程 ServerSocket API Socket API 示例一:   网络编程指的

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

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

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

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

    2024年02月15日
    浏览(42)
  • 网络编程『socket套接字 ‖ 简易UDP网络程序』

    🔭个人主页: 北 海 🛜所属专栏: Linux学习之旅、神奇的网络世界 💻操作环境: CentOS 7.6 阿里云远程服务器 在当今数字化时代,网络通信作为连接世界的桥梁,成为计算机科学领域中至关重要的一部分。理解网络编程是每一位程序员必备的技能之一,而掌握套接字编程则

    2024年02月04日
    浏览(33)
  • 【网络通信】socket编程——TCP套接字

    TCP依旧使用代码来熟悉对应的套接字,很多接口都是在udp中使用过的 所以就不会单独把他们拿出来作为标题了,只会把第一次出现的接口作为标题 通过TCP的套接字 ,来把数据交付给对方的应用层,完成双方进程的通信 在 tcpServer.hpp 中,创建一个命名空间 yzq 用于封装 在命名

    2024年02月13日
    浏览(29)
  • 【JavaEE初阶】 网络编程基础与Socket套接字

    用户在浏览器中,打开在线视频网站,如腾讯看视频,实质是通过网络,获取到网络上的一个视频资源。 与本地打开视频文件类似,只是视频文件这个资源的来源是 网络 。 相比本地资源来说,网络提供了更为丰富的网络资源: 所谓的网络资源,其实就是在网络中可以获取

    2024年02月05日
    浏览(41)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包