c++每日八股文---socket实现简单的TCP通信

一 、流程
在这里插入图片描述
二、网络字节序

uint32_t htonl(uint32_t hostlong)    //本地字节序转网络字节序(IP)
uint16_t htons(unit16_t hsoshort)    //本地字节序转网络字节序(端口)
uint32_t ntohl(unit32_t netlong)    //网络字节序转本地字节序(端口)
uint16_t ntohs(unit16_t netshort)    //网络字节序转本地字节序(端口)

IP地址转换函数(常用的)

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

把点分十进制的ip转换为网络字节序
af:当前的ip协议类型AF_INET AF_INET6
src:传入参数 IP地址(点分十进制)
dst:传出参数 转换后的网络字节序的IP地址
成功返回1 异常返回0(src指向的不是有效的IP地址) 失败返回-1

 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:字节序的大小

三、函数API
1、

struct sockaddr 
struct sockaddr_in {
               sa_family_t    sin_family; /* address family: AF_INET */
               in_port_t      sin_port;   /* port in network byte order */
               struct in_addr sin_addr;   /* internet address */
           };
           /* Internet address. */
           struct in_addr {
               uint32_t       s_addr;     /* address in network byte order */
           };

初始化的时候用下面的结构体初始化,传参的时候在强转为上面结构体的指针
成员初始化:
sin_family :AF_INET/AF_INET6(ipv4/ipv6)
sin_port:网络字节序的端口号
sin_addr.s_addr:(结构体嵌套结构体)网络字节序的IP地址 一般情况下赋值方法为

serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

自动取当前系统中有效的IP地址。 默认整形,进行字节序转换

2、

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

socket函数:创建一个套接字
domain:选用的IP地址协议 通常为AF_INET(IPV4)、AF_INET6(IPV6)。
type:创建套接字所选用的数据传输协议 SOCK_STREAM、SOCK_DGRAM
protocol:所选用的协议的代表协议,默认为0(根据前面的所选的类型自动确定)(TCP/UDP)
返回值:成功:新套接字所对应的文件描述符 。失败:返回-1。
3、

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

bind:给socket绑定地址结构(IP + 端口号)
sockfd:socket函数的返回值
addr:传入参数(struct sockaddr *)&addr (进行强转)
addrlen:sizeof(addr)地址结构的大小
返回值:成功:0 。 失败-1。
4、

int listen(int sockfd, int backlog)

listen:设置同时与服务器链接的上限数(同时进行三次握手的客户端数量)
sockfd:socket函数的返回值
backlog:同时连接的数值
5、

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

accept:阻塞等待客户端连接,成功返回一个与客户端链接的socket文件描述符(新的文件描述符)
sockfd:socked函数的返回值。
addr:传出参数。成功与服务器建立链接的客户端的地址结构(IP+PORT)。
addrlen:传入传出参数。入:addr的大小 。 出:客户端addr的实际大小。

clit_addr_len = sizeof(clit_addr);

传参的时候传&clit_addr_len。
返回值:返回能与服务器进行数据通信的socket对应的文件描述符。失败返回-1。
6、

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

connect:与服务器建立连接
sockfd:客户端scoket函数的返回值
addr:传入参数 服务器的地址结构
addrlen:服务器地址结构的大小。
返回值: 成功0 失败-1。

三、代码实现
实现功能:客户端输入小写字符,服务器将小写字母转换为大写字母返回给客户端并打印。
服务器端:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/socket.h>
  4 #include<string.h>
  5 #include<unistd.h>
  6 #include<ctype.h>
  7 #include<arpa/inet.h>
  8 
  9 #define SERV_PORT  9257
 10 
 11 int main()
 12 {
 13     int lfd = 0;
 14     int cfd = 0;
 15     char buf[BUFSIZ], client_IP[1024];
 16     //定义结构体并初始化
 17     struct sockaddr_in serv_addr, clit_addr;
 18     socklen_t clit_addr_len;
 19     serv_addr.sin_family = AF_INET;
 20     serv_addr.sin_port = htons(SERV_PORT);
 21     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 22 
 23     //创建socket
 24     lfd = socket(AF_INET, SOCK_STREAM, 0);
 25     if (lfd == -1){
 26         perror("socket error");
 27         exit(1);
 28     }
 29 
 30     //绑定
 31     int ret = bind(lfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
 32     if (ret == -1){
 33         perror("bid error");
 34         exit(1);
 35     }
 36 
 37     ret = listen(lfd, 128);
 38     if (ret == -1){
 39         perror("listen error");
 40         exit(1);
 41     }
 42 
 43     //阻塞监听客户端建立链接 返回新的文件描述符
 44     clit_addr_len = sizeof(clit_addr);
 45     cfd = accept(lfd, (struct sockaddr *)&clit_addr, &clit_addr_len);
 46     if (cfd == -1){
 47         perror("accept error");
 48         exit(1);
 49     }
 50     printf("client ip:%s port:%d\n",
 51             inet_ntop(AF_INET, &clit_addr.sin_addr.s_addr, client_IP, sizeof(client_IP)),
 52             ntohs(clit_addr.sin_port));
 53 
 54     //服务器工作:读文件
 55     int i = 0;
 56     while(1){
 57         ret = read(cfd, buf, sizeof(buf));
 58         write(STDOUT_FILENO, buf, ret);
 59         for(i = 0; i < ret; i ++){
 60             buf[i] = toupper(buf[i]); //小写转大写
 61         }
 62         write(cfd, buf, ret);
 63     }
 64 
 65     close(cfd);
 66     close(lfd);
 67     return 0;
 68 }

客户端:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<string.h>
  5 #include<sys/socket.h>
  6 #include<arpa/inet.h>
  7 
  8 #define SERV_PORT 9257
  9 
 10 int main()
 11 {
 12     int cfd;
 13     int conter = 10;
 14     char buf[BUFSIZ];
 15 
 16     struct sockaddr_in  serv_addr; //服务器的地址结构
 17     serv_addr.sin_family = AF_INET;
 18     serv_addr.sin_port = htons(SERV_PORT);
 19     inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
 20     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 21 
 22     cfd = socket(AF_INET, SOCK_STREAM, 0);
 23     if (cfd == -1){
 24         perror("socket error");
 25         exit(1);
 26     }
 27 
 28     int ret = connect(cfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
 29     if (ret != 0){
 30         perror("connect error");
 31         exit(1);
 32     }
 33     while(conter--){
 34         write(cfd, "hello\n", 6);
 35         ret = read(cfd, buf, sizeof(buf));
 36         write(STDOUT_FILENO, buf, ret);
 37         sleep(1);
 38     }
 39     close(cfd);
 40     return 0;
 41 }
 42 

程序运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值