scoket套接字---server的实现

本文介绍了Linux中套接字作为文件类型的概念,不占用存储空间,可用于IO操作。文章详细阐述了TCP套接字的创建、绑定、监听、接受和连接等步骤,以及相关函数如htons和htonl的作用,展示了服务器端和客户端的简单代码示例。
摘要由CSDN通过智能技术生成

1 套接字的概念
Linux当中的一种文件类型,伪文件,不占用存储空间,可进行IO操作,可间接看做文件描述符使用。

2 通信方式有哪几种,Socket有什么区别
通信方式:信号量 管道 消息队列 共享内存 套接字
区别:套接字支持网络上两台以上的设备进行通信,其他其中只能在一台设备上
原因: Socket有双个缓冲区

原文链接:https://blog.csdn.net/weixin_44972997/article/details/115751075

本地网络字节序:

socket模型创建流程分析

        

 转换函数 :toupper

函数:

int socket(int domain, int type, int proto‐col);

int domain :AF_UNIX AF_INET 、AF_INET6. 选用的协议

type:SOCK_STREAM SOCK_DGRAM 流(TCP)、报(UDP)

proto‐col:0

返回值:成功:新 套接字所对应的文件描述符

失败:-1;

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

sockfd:socket返回值

struct sockadd_in addr:

addr.sin_family = AF_INET;

addr.sin_port = htons(8888);

addr.sin_addr.s_addr = htonl(INADDR_ANY);

const struct sockaddr *addr:&addr

addrlen:地址结构的大小

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

sockfd:

backlog:上限数字

int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen) 能与服务器进行数据通信的socket

addr:传出参数 成功与服务器建立连接的哪个客户端的地址结构

int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen )用来与服务器进行链接

sockfd:

addr:传入参数 服务器的地址结构

addrlen:服务器的地址结构大小

成功:0

//服务端程序
#include <ctype.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#define SERV_PORT 9527
#define BUFSIZE 1024
int main()
{
	int cfd;
	int lfd = socket(AF_INET,SOCK_STREAM,0);//TCP协议
	if(lfd==-1)
	{
		perror("socket");
		exit(-1);
	}
	
	char buf[BUFSIZE];
	//创建一个服务器的地址结构
	struct sockaddr_in s_addr,clit_addr;//shezhi fuwuduan kehuduan 
	s_addr.sin_family = AF_INET;
 	 //取值范围0~65535
	s_addr.sin_port = htons(SERV_PORT);//htons:16位  htonl:32位 本地字节转网络字节htonsl
	s_addr.sin_addr.s_addr = htons(INADDR_ANY);
	//2、绑定自己IP和端口号
	bind(lfd,(struct sockaddr*)&s_addr,sizeof(s_addr));
	//3.监听
	listen(lfd,128);

	int clit_addr_len = sizeof(clit_addr);
	//4.能与服务器进行通信的socket
	 cfd = accept(lfd,(struct sockaddr*)&clit_addr,&clit_addr_len);
	if(cfd ==-1)
	{
		perror("accept");
		exit(-1);
	}
	printf();
	//5.读操作
	while(1)
	{
	int ret  = read(cfd,buf,sizeof(buf));
	write(STDOUT_FILENO,buf,ret);
	for(int i= 0;i<ret;i++)
	{
		buf[i] = toupper(buf[i]);
		//write(cfd,buf,ret);
	}
	}
	close(lfd);
	close(cfd);
	return 0;//错误返回-1
}

CS模型的实现

TCP通信流程 分析:

server:服务器

  1. socket()

  2. bind()

  3. listen()

  4. accep()

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

  6. 小转大 toupper()

  7. write()

  8. close()

client:

  1. socket()

  2. connect()

  3. write()

  4. read()

  5. 显示读取结果

函数原型:

 //1.
 int socket(int domain, int  type,  int  proto‐col);
 ​
 
 //1.
 int domain :AF_UNIX AF_INET 、AF_INET6.  选用的协议
 ​
 //2.
 type:SOCK_STREAM SOCK_DGRAM   流(TCP)、报(UDP)
 ​
 //3.
 proto‐col:0
 ​
 返回值:成功:套接字所对应的文件描述符
 •      失败:-1;
 //2.给socket绑定一个地址结构(IP+端口号)
 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
 ​
 //1.
 sockfd:socketfd
 ​
 //2.
 struct sockadd_in addr:
 addr.sin_family = AF_INET;
 addr.sin_port = htons(8888);
 //8888用于客户端连接
 addr.sin_addr.s_addr = htonl(INADDR_ANY);
 ​
 
//3
htonl() 是一个函数族中的一个成员,用于将主机字节序的 16 位整数转换为网络字节序(大端字节序)的 16 位整数。
 这个函数族包括以下函数:
 htons():将主机字节序的 16 位整数转换为网络字节序的 16 位整数。
 htonl():将主机字节序的 32 位整数转换为网络字节序的 32 位整数。
 ntohs():将网络字节序的 16 位整数转换为主机字节序的 16 位整数。
 ntohl():将网络字节序的 32 位整数转换为主机字节序的 32 位整数。
 const struct sockaddr *addr:&addr;
 addrlen:地址结构的大小
 ​
 //4.监听   监听上限
 listen(int sockfd,int backlog)设置同时与服务器建立连接的上限数(同时进行3次握手的客户端数量)
 //1.监听
 sockfd:
 //2.监听上限
 backlog:上限数字

 //5.阻塞连接  服务器端用于接受客户端连接
 int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen)         能与服务器进行数据通信的socket
 ​
 addr:传出参数 成功与服务器建立连接的哪个客户端的地址结构

获取客户端地址结构:

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

参数说明如下:

  • af:地址族(Address Family),可以是 AF_INET(IPv4)或 AF_INET6(IPv6)。

  • src:指向存储 IP 地址的结构体的指针,可以是 struct in_addr*(IPv4)或 struct in6_addr*(IPv6)。

  • dst:指向保存转换后的 IP 地址字符串的缓冲区。

  • size:缓冲区的大小,确保足够存储转换后的 IP 地址。

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

参数说明如下:

  • af:地址族(Address Family),可以是 AF_INET(IPv4)或 AF_INET6(IPv6)。

  • src:指向以字符串形式表示的 IP 地址的指针。

  • dst:指向存储转换后 IP 地址的结构体的指针,可以是 struct in_addr*(IPv4)或 struct in6_addr*(IPv6)。

具体代码实现:

 //server.c
 //服务端程序
 #include <ctype.h>
 #include <stdio.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <unistd.h>
 #include <stdlib.h>
 #define SERV_PORT 9527
 #define BUFSIZE 1024
 int main()
 {
     int cfd;
     int lfd = socket(AF_INET,SOCK_STREAM,0);//TCP协议
     if(lfd==-1)
     {
         perror("socket");
         exit(-1);
     }
     
     char buf[BUFSIZE];
     char client_IP[1024];
     //创建一个服务器的地址结构
     struct sockaddr_in s_addr,clit_addr,clit_IP;//shezhi fuwuduan kehuduan 
     s_addr.sin_family = AF_INET;
      //取值范围0~65535
     s_addr.sin_port = htons(SERV_PORT);//htons:16位  htonl:32位 本地字节转网络字节htonsl
     s_addr.sin_addr.s_addr = htons(INADDR_ANY);
     //2、绑定自己IP和端口号
     bind(lfd,(struct sockaddr*)&s_addr,sizeof(s_addr));
     //3.监听
     listen(lfd,128);
 ​
     int clit_addr_len = sizeof(clit_addr);
     //4.能与服务器进行通信的socket
      cfd = accept(lfd,(struct sockaddr*)&clit_addr,&clit_addr_len);
     if(cfd ==-1)
     {
         perror("accept");
         exit(-1);
     }
     printf("client ip:%s\n",inet_ntop(AF_INET,&(clit_addr.sin_addr),client_IP,sizeof(client_IP)));
     printf("client port:%d\n",ntohs(clit_addr.sin_port));
     //5.读操作
     while(1)
     {
     int ret  = read(cfd,buf,sizeof(buf));
     write(STDOUT_FILENO,buf,ret);
     for(int i= 0;i<ret;i++)
     {
         buf[i] = toupper(buf[i]);
         //write(cfd,buf,ret);
     }
     }
     close(lfd);
     close(cfd);
     return 0;//错误返回-1
 }
 ​
 //客户端
 // date: 2023年07月15日 星期六 10时46分10秒
 /// player: wenrou
 /// // path: /mnt/hgfs/LuinxFile/GEC_2301/06_网络编程/01_Socket编程/client.c /
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include <stdlib.h>
 #include <string.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #define SERV_PORT 9527
 int main()
 {
     char buf[BUFSIZ];
     int cfd = socket(AF_INET,SOCK_STREAM,0);
     if(cfd == -1)
     {
         perror("client socket");
     }
     struct sockaddr_in serv_addr;
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_port = htons(SERV_PORT);
     inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin_addr.s_addr);
     //serv_addr.sin_addr.s_addr = htons(INADDR_ANY)//INADDR_ANY 
       //int ret = connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
       int ret = connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
     if(ret==-1)
     {
         perror("connect");
     }
     int cout = 10;
     while(--cout)
     {
     
         write(cfd,"hello",5);
         ret = read(cfd,buf,sizeof(buf));
     write(STDOUT_FILENO,buf,ret);
     }
     close(cfd);
     return 0;
 }
 ​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值