Linux系统下建立Socket聊天服务器

目录

1.服务器结构

2.各模块函数

2.1 socket函数 

2.2 bind函数

2.3 Listen函数

2.4 accept函数

2.5 接收发送函数

2.6 close函数

2.7 connect函数

3 代码段

3.1 服务器代码


1.服务器结构

使用socket的API函数编写服务端和客户端程序的步骤图示:

2.各模块函数

服务器:

2.1 socket函数 

使用socket会建立一个服务器文件描述符

  • 成功: 返回一个大于0的文件描述符
  • 失败: 返回-1, 并设置errno
int socket(int domain, int type, int protocol);

domain: 协议版本

AF_INET IPV4
AF_INET6 IPV6
AF_UNIX AF_LOCAL本地套接字使用

type:协议类型

SOCK_STREAM 流式, 默认使用的协议是TCP协议
SOCK_DGRAM  报式, 默认使用的是UDP协议

protocal:

一般填0, 表示使用对应类型的默认协议.

2.2 bind函数

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

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

函数描述: 将socket文件描述符和IP,PORT绑定。

sockfd为socket的返回值,文件描述符

struct sockaddr* addr结构体可以用下面的

struct sockaddr_in serv;
serv.sin_family = AF_INET;//选择使用的网络协议
serv.sin_port = htons(8888);//绑定本机端口,通常占2字节。注意:端口号尽量不要填1024以前的数字,因为可以被系统预留了。
serv.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY: 表示使用本机任意有效的可用IP
如果想自己指定ip地址作为服务器连接就需要这个:
inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
或者inet_aton("127.0.0.1", &serv.sin_addr);
或者这个:addr.sin_addr.s_addr = inet_addr("192.168.239.1");

 同时在使用addr时,先对其进行清空memset。

“端口号所谓的端口,就好像是门牌号一样,客户端可以通过ip地址找到对应的服务器端,但是服务器端是有很多端口的,每个应用程序对应一个端口号,通过类似门牌号的端口号,客户端才能真正的访问到该服务器。为了对端口进行区分,将每个端口进行了编号,这就是端口号。”
  你可能对出现的htons()、htonl和inet_pton()不知道是何意,在网络传输中,不同的机器端不一样,有的机器是大端有的机器是小端。这些函数是为了帮助你在传输网络数据的时候统一格式。(没有超过一个字节不需要转)

大端: 低位地址存放高位数据, 高位地址存放低位数据(也叫网络字节序)
小端: 低位地址存放低位数据, 高位地址存放高位数据(也叫小端字节序)

网络中传输使用的是大端法,如果机器使用的是小端,则需要进行大小端的转换。
  下面4个函数就是进行大小端转换的函数:

  #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表示主机host, n表示网络network, s表示short, l表示long
上述的几个函数, 如果本来不需要转换函数内部就不会做转换.

IP地址转换函数:

p->表示点分十进制的字符串形式
to->到
n->表示network网络

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

函数说明: 将字符串形式的点分十进制IP转换为大端模式的网络IP(整形4字节数)
参数说明:

af: AF_INET
src: 字符串形式的点分十进制的IP地址
dst: 存放转换后的变量的地址

如192.168.232.145, 先将4个正数分别转换为16进制数,
  192—>0xC0 168—>0xA8 232—>0xE8 145—>0x91
  最后按照大端字节序存放: 0x91E8A8C0, 这个就是4字节的整形值.

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


函数说明: 网络IP转换为字符串形式的点分十进制的IP
参数说明:

af: AF_INET
src: 网络的十六进制的IP地址
dst: 转换后的IP地址,一般为字符串数组
size: dst的长度
成功--返回执行dst的指针
失败--返回NULL, 并设置errno

如 IP地址为010aa8c0, 转换为点分十进制的格式:
  01---->1 0a---->10 a8---->168 c0---->192
  由于从网络中的IP地址是高端模式, 所以转换为点分十进制后应该为: 192.168.10.1

2.3 Listen函数

int listen(int sockfd, int backlog);

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

函数描述: 将套接字由主动态变为被动态,也就是设置为监听文件描述符。

参数说明:

sockfd: 调用socket函数返回的文件描述符
backlog: 同时请求连接的最大个数(还未建立连接)  设置为6/7
 注意:在linux系统中,这里代表全连接队列(已连接队列)的数量。在unix系统种,这里代表全连接队列(已连接队列)+ 半连

2.4 accept函数

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

函数说明:获得一个连接, 若当前没有连接则会阻塞等待.

sockfd: 调用socket函数返回的文件描述符
addr: 传出参数, 保存客户端的地址信息。如果不关心可以传NULL。
addrlen: 传入传出参数,  addr变量所占内存空间大小,这个传出的时候会告诉我们填充的多少的内容。如果不关心可以传NULL。

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

accept函数是一个阻塞函数, 若没有新的连接请求, 则一直阻塞。从已连接队列中获取一个新的连接, 并获得一个新的文件描述符, 该文件描述符用于和客户端通信. (内核会负责将请求队列中的连接拿到已连接队列中)。

2.5 接收发送函数

接下来就可以使用write和read函数进行读写操作了。除了使用read/write函数以外, 还可以使用recv和send函数。

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);    
//对应recv和send这两个函数flags直接填0就可以了.

fd为accept返回的fd,count为字节,flag写0

注意: 如果写缓冲区已满, write也会阻塞, read读操作的时候, 若读缓冲区没有数据会引起阻塞.
 

2.6 close函数

  最后通讯完之后记得close()文件描述符,关闭文件描述符后就断开了连接,就从已连接队列里面去掉了.。

2.7 connect函数

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

函数说明: 连接服务器,client.c使用connect函数前应该先使用socket函数得到文件描述符fd。
函数参数:

addr设置为服务端一样的就行,进行传入

sockfd: 调用socket函数返回的文件描述符
addr: 服务端的地址信息
addrlen: addr变量的内存大小   用sizeof

返回值:

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

主要用于客户端连接,客户端不需要绑定端口、ip什么的,因为只要能连上然后传输接收数据就行。
然后直接用sockfd进行读写就行。

3 代码段

3.1 服务器代码

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>

int main(void)
{
	int s_fd,ss_fd,nread,len;
	char buf[32];
	char msg[32];
	struct sockaddr_in s_ddr;  //build server msg
	struct sockaddr_in c_ddr;  //save clinet msg
	s_fd= socket(AF_INET, SOCK_STREAM, 0);//1.build a soket specified
	if(s_fd==-1){
		perror("error is");
	}
	//2.build all bind
	s_ddr.sin_family=AF_INET;
	s_ddr.sin_port=htons(8880);
	s_ddr.sin_addr.s_addr=htonl(INADDR_ANY);
	//give the bind
	bind(s_fd,(struct sockaddr *)&s_ddr,sizeof(s_ddr));
	//3.waite for client
	listen(s_fd,8);
	//4.accept come and connect for once
	len=sizeof(c_ddr);
	while(1){                        //这里用while1是为了一直可以被连接
		ss_fd=accept(s_fd,(struct sockaddr *)&c_ddr,&len);  
		printf("conect succese!==========\r\n");
		//5.read from connect ss_fd
		if(fork()==0){               //创建一个子进程(服务员)去接待client
			if(fork()==0){  //fork is zero is child pid   //创建一个子进程去等待发送
				//5.1  send
				while(1){
					memset(msg,0,32);	
					printf("input:");
					gets(msg);
					send(ss_fd,msg,32,0);
				}

			}
			//5.2 read	                                    //在父进程中等待接收数据
			while(1){
				memset(buf,'\0',32);
				nread=read(ss_fd,&buf,32);
				printf("server  receved :%s \r\n",buf); 
			}
		}

	}
	close(ss_fd);
	close(s_fd);
	return 0;
}

3.2 客户端代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>


int main(int argc,char *argv[])
{
	int flag,s_fd,n_read;
	struct sockaddr_in c_ddr;
	char readbuf[32];
	char msg[32];
	//1.build socket
	s_fd=socket(AF_INET,SOCK_STREAM,0);
	
	//2.0 prepare server addr
	memset(&c_ddr,0,sizeof(c_ddr)); //clear c_ddr
	c_ddr.sin_family=AF_INET;
	c_ddr.sin_port=htons(8880);
	inet_aton("192.168.102.141",&c_ddr.sin_addr);
	
	//2.connect server get s_fd
			
	if(connect(s_fd,(struct sockaddr *)&c_ddr,sizeof(c_ddr))==-1){
		perror("error");
	}
	printf("connect success==============\r\n");
	while(1){                                      //while1父进程一直等待读数据        
		//recv  will block  
		memset(readbuf,0,32);
		read(s_fd,readbuf,32);
		printf("form server:%s\r\n",readbuf);
		
		//send
		if(fork()==0){  //fork is zero is child pid   //子进程一直(while1)等待发数据
			while(1){
				memset(msg,0,32);
				printf("input :::::");
				gets(msg);
				send(s_fd,msg,32,0);
			}
		}
	}
	close(s_fd);

	return 0;
} 

参考博文:

Linux环境下socket服务器搭建_socket搭建linux_master cat的博客-CSDN博客

socket编程 服务器_socket 服务器_不爱学习的王小二的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/100196.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TensorFlow 的基本概念和使用场景介绍

文章目录 一、TensorFlow基本概念1. 张量&#xff08;Tensor&#xff09;2. 计算图&#xff08;Computation Graph&#xff09;3. 会话&#xff08;Session&#xff09; 二、TensorFlow使用场景1. 机器学习&#xff08;Machine Learning&#xff09;2. 计算机视觉&#xff08;C…

阿晨的运维笔记 | CentOS部署Docker

使用yum安装 # step 1: 安装必要的一些系统工具 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 # Step 2: 添加软件源信息 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # Step 3: 更新并安装 …

DVWA靶场搭建

目录 配置环境&#xff1a; 1、将下载好的压缩包放置php的WWW根目录下 2、改文件配置 3、查看mysql用户名和密码&#xff0c;将其修改值靶场配置文件中 4、完成后我们就可以在浏览器输入127.0.0.1/dvwa进入靶场 测试XSS注入&#xff1a; 配置环境&#xff1a; githhub下…

《CTFshow-Web入门》09. Web 81~90

Web 入门 索引web81题解 web82题解原理 web83题解 web84题解 web85题解 web86题解 web87题解原理 web88题解 web89题解 web90题解 ctf - web入门 索引 web81&#xff1a;include() 利用&#xff0c;一句话木马之 Nginx 日志利用。web82~86&#xff1a;include() 利用&#xff…

Java“牵手”京东店铺所有商品API接口数据,通过店铺ID获取整店商品详情数据,京东店铺所有商品API申请指南

京东平台店铺所有商品数据接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取京东整店的商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片、价格信息等详细信息 。 获取店铺所有商品接口API是一种用于获取电商平台上商品详…

Java中网络的基本介绍。网络通信,网络,ip地址,域名,端口,网络通信协议,TCP/IP传输过程,网络通信协议模型,TCP协议,UDP协议

- 网络通信 概念&#xff1a;网络通信是指通过计算机网络进行信息传输的过程&#xff0c;包括数据传输、语音通话、视频会议等。在网络通信中&#xff0c;数据被分成一系列的数据包&#xff0c;并通过网络传输到目的地。在数据传输过程中&#xff0c;需要确保数据的完整性、准…

机器人编程怎么入门?

机器人已经在我们中间存在了二三十年。如今&#xff0c;机器人在我们的文化中比以往任何时候都更加根深蒂固。大多数机器人机器用于各种装配线&#xff0c;或在世界各地的矿山或工业设施中执行密集的物理操作。 还有一些家用机器人&#xff0c;工程师正在对机器人进行编程&…

表白墙程序

目录 一、页面代码部分 二、设计程序 二、实现 doPost​编辑 三、实现 doGet 四、前端代码部分 五、使用数据库存储数据 一、页面代码部分 在之前的一篇博客中&#xff0c;已经写过了表白墙的页面代码实现&#xff0c;这里就不再重复了 页面代码如下&#xff1a; <!…

【计算机组成 课程笔记】1.2 冯·诺伊曼结构

课程链接&#xff1a; 计算机组成_北京大学_中国大学MOOC(慕课) 1 - 2 - 102-冯诺依曼结构的要点&#xff08;13-59--&#xff09;_哔哩哔哩_bilibili 现代的计算机形态各异&#xff0c;但究其本质&#xff0c;几乎全部采用了冯诺依曼结构。要了解计算机&#xff0c;首先要知道…

华为数通方向HCIP-DataCom H12-821题库(拖拽题,知识点总结)

以下是我在现有题库中整理的需要重点关注的考点内容,如有遗漏小伙伴可以留言补充。

【仿牛客论坛java项目】第五章 Kafka,构建TB级异步消息系统:阻塞队列、Kafka入门、Spring整合Kafka、发送系统通知、显示系统通知

这里写自定义目录标题 一、阻塞队列简单的阻塞队列测试案例总结阻塞队列 二、Kafka入门1、基础知识Kafka术语消息队列实现方式两种 2、配置3、启动全部命令启动 zookeeper 服务器再启动 kafka 服务器创建Topic关闭 4、总结Kafka的特点Kafka的术语 三、 Spring整合Kafka导入依赖…

R语言绘图相关函数(含实例)

目录 plot:可用于创建多种类型的图形 dev.new():新建画板 hist&#xff1a;绘制直方图 dotchart&#xff1a;绘制点图的函数 pie:绘制饼图 pair&#xff1a;绘制散点图矩阵 boxplot&#xff1a;绘制箱线图 scatterplot3D&#xff1a; 绘制三维散点图 par&#xff1a;修…

CTFhub-文件上传-前端验证

burp 抓包 --> 重发--> 查看源代码 用 GodZilla 生成木马 文件名为 1.php.jsp 上传-->抓包-->改包 (删掉 .jpg) --> 点击 放行 木马文件位置为&#xff1a;http://challenge-f0531d0c27641130.sandbox.ctfhub.com:10800/upload/1.php 用 蚁剑连接 ctfhub{4743b…

【Go 基础篇】Go语言结构体实例的创建详解

在Go语言中&#xff0c;结构体是一种强大的数据类型&#xff0c;允许我们定义自己的复杂数据结构。通过结构体&#xff0c;我们可以将不同类型的数据字段组合成一个单一的实例&#xff0c;从而更好地组织和管理数据。然而&#xff0c;在创建结构体实例时&#xff0c;有一些注意…

百度抓取香港服务器抓取超时是什么情况?

​ 网络延迟导致抓取超时 网络延迟是指从发送请求到接收响应之间的时间延迟。如果网络延迟过高&#xff0c;服务器可能无法及时响应请求&#xff0c;导致超时。在香港服务器上抓取数据时&#xff0c;如果网络延迟过高&#xff0c;可能会出现抓取超时的情况。 服务器负载过高可能…

设计模式-原型模式详解

文章目录 前言理论基础1. 原型模式定义2. 原型模式角色3. 原型模式工作过程4. 原型模式的优缺点 实战应用1. 原型模式适用场景2. 原型模式实现步骤3. 原型模式与单例模式的区别 原型模式的变体1. 带有原型管理器的原型模式2. 懒汉式单例模式的原型模式实现3. 细粒度原型模式 总…

系统架构技能之设计模式-抽象工厂模式

一、上篇回顾 上篇我们主要讲述了简单工厂模式和工厂模式。并且分析了每种模式的应用场景和一些优缺点&#xff0c;我们现在来回顾一下&#xff1a; 简单工厂模式&#xff1a;一个工厂负责所有类型对象的创建&#xff0c;不支持无缝的新增新的类型对象的创建。 工厂模式&…

JVM面试核心点

一、JDK体系 二、JVM体系 三、JVM内存模型 public class Math {public static final int data 666;public static UserEntity user new UserEntity();public int compute() { // 一个方法对应一块栈帧内存区域int a 1;int b 2;int c (ab)*10;return c;}public static voi…

Angular安全专辑之三 —— 授权绕过,利用漏洞控制管理员账户

这篇文章是针对实际项目中所出现的问题所做的一个总结。简单来说&#xff0c;就是授权绕过问题&#xff0c;管理员帐户被错误的接管。 详细情况是这样的&#xff0c;我们的项目中通常都会有用户身份验证功能&#xff0c;不同的用户拥有不同的权限。相对来说管理员账户所对应的…

openGauss学习笔记-57 openGauss 高级特性-并行查询

文章目录 openGauss学习笔记-57 openGauss 高级特性-并行查询57.1 适用场景与限制57.2 资源对SMP性能的影响57.3 其他因素对SMP性能的影响57.4 配置步骤 openGauss学习笔记-57 openGauss 高级特性-并行查询 openGauss的SMP并行技术是一种利用计算机多核CPU架构来实现多线程并行…