TCP套接字,实现客户端,服务器的模拟互发信息

端口号:
端口号(port)是传输层协议的内容.
1. 端口号是一个二字节16位的整数;
2. 端口号是用来表示一个进程,表示当前数据交给哪一个进程来处理;
3. IP地址 + 端口号可以网络上某一台主机的某一个进程;
4. 一个端口号只能被一个进程占用;

	注意: 一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定

TCP协议
TCP(Transmission Control Protocol 传输控制协议)

  • 传输层协议
  • 有连接
  • 可靠连接
  • 面向字节流
    UDP协议
    UDP(User Datagram Protocol 用户数据报协议)
  • 传输层协议
  • 无连接
  • 不可靠传输
  • 面向数据报
    socket编程接口
 创建socket文件描述符(tcp/udp,客户端+服务端)
 int socket(int domain, int type, int protocol);
	Domain:地址域
	Sock_STREAM流式套接字,默认协议TCP,不支持UDP
	Sock_DGRAM 数据报套接字,默认协议UDP,不支持TCP
	Type: 套接字类型
	0:使用默认类型协议
	Protocol:协议类型
 绑定端口号 (TCP/UDP, 服务器)
 int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
 	Sockfd: 创建套接字返回的描述符
	Addr: 地址信息
	Addrlen: 地址信息长度
	返回值:0 失败:-1
 socklen_t address_len); 
 建立连接 (TCP, 客户端)
 int connect(int sockfd, const struct sockaddr *addr,  socklen_t addrlen);                                                                                                                                     
 开始监听socket (TCP, 服务器)
 int listen(int socket, int backlog);
 建立连接 (TCP, 客户端)
 int connect(int sockfd, const struct sockaddr *addr,  socklen_t addrlen);  
 接收请求 (TCP, 服务器)
 int accept(int socket, struct sockaddr* address,  socklen_t* address_len);
 发送数据
Send()
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
Sockfd: 操作句柄,套接字描述符
Buf: 想要发送的数据
Len: 要发送的数据长度(不一定是字节长度)
Flags: 0--默认阻塞发送
Daddr: 目的段地址信息--标识数据要发送到哪里去
Addrlen:实际发送的数据长度 失败:-1
接受数据
Recv(sockfd, buf, len, flag)
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//名称                  目的
 AF_INET           IPv4网络通信
 |AF_INET6          IPv6网络通信
 AF_PACKET          链路层通信
 AF_UNIX, AF_LOCAL   本地通信
type
SOCK_ STREAM      字节流套接字
SOCK DGRAM        数据报套接字
SOCK_ .SEQPACKET  有序分组套接字
SOCK_ RAW         原始套接字
protocol                                                             
IPPROTO_TCP       TCP传输协议                                  
IPPTOTO_UDP       UDP传输协议                                 
IPPROTO_SCTP      STCP传输协议                                      
IPPROTO_TIPCTCP   TIPC传输协议

字节序转换函数
数字的字节序转换: 主机字节序转换为网络字节序
4个字节的数据
uint32_t htonl(uint32_t hostlong);
2个字节的数据(不可用4字节转换)
uint16_t htons(uint16_t hostshort);
数字的字节序转换: 网络字节序转换为主机字节序
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
将点分十进制IP地址字符串转换为网络字节序IP地址
in_addr_t inet_addr(const char *cp);
int inet_pton(int af, const char *src, void *dst);
将网络字节序转换为字符串点分式十进制IP地址
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
char *inet_ntoa(struct in_addr in);
快速判断断开
原理:
TCP的连接内部管理中,内建有保活机制;
当长时间没有数据往来的时候,每隔一段时间向对方发送一个保活探测包,要求对方回复,当多次发送的保活探测包都没有响应,则认为连接断开
表现:
若连接断开,则recv会返回0,send会触发异常SIGPIPE
recv返回0,不是没有数据的意思.而指的是连接断开
因为TCP面向字节流.
封装TCP函数TcpScoket.hpp

 | |  1 #include <stdio.h>
 | |  2 #include <string>
 | |  3 #include <string.h>
 | |  4 #include <unistd.h>
 | |  5 #include <sys/socket.h>
 | |  6 #include <stdlib.h>
 | |  7 #include <netinet/in.h>
 | |  8 #include <arpa/inet.h>
 | |  9 #include <errno.h>
 | | 10 #include <iostream>
 | | 11 //创建socket文件描述符(tcp/udp,客户端+服务端)
 | | 12 //  int socket(int domain, int type, int protocol);                                                                                                              
 | | 13 //建立连接 (TCP, 客户端)
 | | 14 //  int connect(int sockfd, const struct sockaddr *addr,  socklen_t addrlen);
 | | 15 //绑定端口号 (TCP/UDP, 服务器)
 | | 16 //  int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
 | | 17 //  socklen_t address_len);
 | | 18 //开始监听socket (TCP, 服务器)
 | | 19 //  int listen(int socket, int backlog);
 | | 20 //建立连接 (TCP, 客户端)
 | | 21 //  int connect(int sockfd, const struct sockaddr *addr,  socklen_t addrlen);  
 | | 22 // 接收请求 (TCP, 服务器)
 | | 23 //  int accept(int socket, struct sockaddr* address,  socklen_t* address_len);
 | | 24 //名称                  目的
 | | 25 //AF_INET           IPv4网络通信
 | | 26 //AF_INET6          IPv6网络通信
 | | 27 //AF_PACKET          链路层通信 
 | | 28 //AF_UNIX, AF_LOCAL   本地通信
 | | 29 
 | | 30 //type
 | | 31 //SOCK_ STREAM      字节流套接字
 | | 32 //SOCK DGRAM        数据报套接字
 | | 33 //SOCK_ .SEQPACKET  有序分组套接字
 | | 34 //SOCK_ RAW         原始套接字
 | | 35                                                                                                                                                                  
 | | 36 //protocol                                                                                                                                                       
 | | 37 //IPPROTO_TCP       TCP传输协议                                                                                                                                  
 | | 38 //IPPTOTO_UDP       UDP传输协议                                                                                                                                  
 | | 39 //IPPROTO_SCTP      STCP传输协议                                                                                                                                 
 | | 40 //IPPROTO_TIPCTCP   TIPC传输协议                                                                                                                                 
 | | 41                                                                                                                                                                  
 | | 42 #define CHECK_RET(q) if((q) == false){return -1;}                                                                                                                
 | | 43                                                                                                                                                                  
 | | 44 typedef struct calculator_info_t {                                                                                                                               
 | | 45     int num1;                                                                                                                                                    
 | | 46     int num2;                                                                                                                                                    
 | | 47     char str[30];                                                                                                                                                
 | | 48     char op;                                                                                                                                                     
 | | 49 }calculator_info;                                                                                                                                                
 | | 50                                                                                                                                                                  
 | | 51 class TcpSocket                                                                                                                                                  
 | | 52 {                                                                                                                                                                
 | | 53 public:                                                                                                                                                          
 | | 54     TcpSocket(): _sockfd(-1){                                                                                                                                    
 | | 55     }                                                                                                                                                            
 | | 56     void SetSockFd(int fd){                                                                                                                                      
 | | 57         _sockfd = fd;                                                                                                                                            
 | | 58     }                                                                                                                                                            
 | | 59     int GetSockFd(){                                                                                                                                             
 | | 60         return _sockfd;                                                                                                                                          
 | | 61     }                                                                                                                                                            
 | | 62     bool Socket(){                                                                                                                                               
 | | 63         _sockfd =  socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);                                                                                                      
 | | 64         if(_sockfd < 0){                                                                                                                                         
 | | 65             perror("socket errno\n");                                                                                                                            
 | | 66             return false;                                                                                                                                        
 | | 67         }                                                                                                                                                        
 | | 68         return true;
 | | 69     }                                                                     
 | | 70     bool Bind(std::string &ip, uint16_t port){                            
 | | 71         struct sockaddr_in addr;                                          
 | | 72         //struct sockaddr_in {                                            
 | | 73         //short int sin_family; //地址族,AF_xxx 在socket编程中只能是AF_IN
 | | 74         //unsigned short int sin_port; // 端口号 (使用网络字节顺序)     
 | | 75         //struct in_addr sin_addr; //存储IP地址 4字节                     
 | | 76         //unsigned char sin_zero[8]; // 总共8个字节,实际上没有什么用,只>
 | | 77         //};                                                              
 | | 78         addr.sin_family = AF_INET;                                        
 | | 79         //网络字节顺序与本地字节顺序之间的转换函数:                      
 | | 80         //    htonl()–“Host to Network Long”                          
 | | 81         //    ntohl()–“Network to Host Long”                          
 | | 82         //    htons()–“Host to Network Short”                         
 | | 83         //    ntohs()–“Network to Host Short”                         
 | | 84         addr.sin_port = htons(port);                                      
 | | 85         addr.sin_addr.s_addr = inet_addr(ip.c_str());                     
 | | 86         //数字的字节序转换: 主机字节序转换为网络字节序                    
 | | 87         //4个字节的数据                                                   
 | | 88         // uint32_t htonl(uint32_t hostlong);                             
 | | 89         //2个字节的数据(不可用4字节转换)                                  
 | | 90         // uint16_t htons(uint16_t hostshort);                            
 | | 91         //数字的字节序转换: 网络字节序转换为主机字节序                    
 | | 92         // uint32_t ntohl(uint32_t netlong);                              
 | | 93         // uint16_t ntohs(uint16_t netshort);                             
 | | 94         //将点分十进制IP地址字符串转换为网络字节序IP地址                  
 | | 95         // in_addr_t inet_addr(const char *cp);                           
 | | 96         // int inet_pton(int af, const char *src, void *dst);             
 | | 97         //将网络字节序转换为字符串点分式十进制IP地址                      
 | | 98         // const char *inet_ntop(int af, const void *src, char *dst, sockl
 | | 99         // char *inet_ntoa(struct in_addr in);                            
 | |100                                                                           
 | |101         socklen_t len = sizeof(struct sockaddr_in);
 | |102         int ret = bind(_sockfd, (const struct sockaddr *)&addr,len);
 | |103         if(ret < 0){                                                      
 | |104             perror("bind errno\n");                                       
 | |105             return false;                                                 
 | |106         }                                                                 
 | |107         return true;                                                      
 | |108     }                                                                     
 | |109     bool Listen(int backlog = 10){                                        
 | |110         // int listen(int socket, int backlog);                           
 | |111         //backlog:最大并发连接数--内核中已完成连接队列的最大节点数        
 | |112         int ret = listen(_sockfd,backlog);                                
 | |113         if(ret < 0){                                                      
 | |114             perror("listen errno\n");                                     
 | |115             return false;                                                 
 | |116         }                                                                 
 | |117         return true;                                                      
 | |118     }                                                                     
 | |119     bool Connect(std::string &ip,uint16_t port){                          
 | |120         //int connect(int sock, const struct sockaddr *addr,  socklen_t ad
 | |121         //addr: 要连接的服务器地址信息                                    
 | |122         struct sockaddr_in addr;                                          
 | |123         addr.sin_family = AF_INET;                                        
 | |124         addr.sin_port = htons(port);                                      
 | |125         addr.sin_addr.s_addr = inet_addr(ip.c_str());                     
 | |126         socklen_t len = sizeof(struct sockaddr_in);                       
 | |127                                                                           
 | |128         int ret = connect(_sockfd,(struct sockaddr*)&addr, len);          
 | |129         if(ret < 0){                                                      
 | |130             perror("connect errno\n");                                    
 | |131             return false;                                                 
 | |132         }                                                                 
 | |133         else{                                                             
 | |134             std:: cout<<"connect success\n";                              
 | |135             return true;
 | |136         }
 | |137     }                                                                     
 | |138     bool Accept(TcpSocket &csock, struct sockaddr_in *addr = NULL){       
 | |139         //在一个套接字上接受一个连接                                      
 | |140         //int accept(int s, struct sockaddr *addr, socklen_t *addrlen);   
 | |141         //addr: 客户端地址信息                                            
 | |142         //len: 输入输出参数,既要指定接受长度,还要接收实际长度             
 | |143         //返回值: 为新客户新建的socket套接字描述符                        
 | |144         //通过这个返回的描述符可以与指定的客户端进行通信                  
 | |145         struct sockaddr_in _addr;                                         
 | |146         socklen_t len = sizeof(struct sockaddr_in);                       
 | |147         int newfd = accept(_sockfd,(struct sockaddr*)&_addr, &len);       
 | |148         if (newfd < 0){                                                   
 | |149             perror("accept errno\n");                                     
 | |150             return false;                                                 
 | |151         }                                                                 
 | |152         if (addr != NULL){                                                
 | |153             memcpy(addr, &_addr, len);                                    
 | |154         }                                                                 
 | |155         csock.SetSockFd(newfd);                                           
 | |156         //_socket--仅用于接受新客户端连接请求                             
 | |157         //newfd--专门用于与客户端进行通信                                 
 | |158         return true;                                                      
 | |159     }                                                                     
 | |160     bool Recv(std::string &buf){                                          
 | |161         char tmp[4096] = {0};                                             
 | |162         //ssize_t recv(int sockfd, void *buf, size_t len, int flags);     
 | |163         //flags:0--默认阻塞接受 MSG_PEEK-获取数据但是不从缓冲区移除       
 | |164         //返回值:实际接受的数据长度 失败:-1 断开连接: 0                   
 | |165         int ret = recv(_sockfd, tmp,4096,0);                              
 | |166         if (ret < 0){                                                     
 | |167             perror("recv error");                                         
 | |168             return false;                                                 
 | |169         }
 | |170         else if (ret == 0){
 | |171             printf("peer shutdown\n");                                    
 | |172             return false;                                                 
 | |173         }                                                                 
 | |174         buf.assign(tmp, ret);                                             
 | |175         return true;                                                      
 | |176     }                                                                     
 | |177     bool Send(std::string &buf){                                          
 | |178         //int send(int s, const void *msg, size_t len, int flags);        
 | |179         int ret = send(_sockfd, buf.c_str(), buf.size(), 0);              
 | |180         if (ret < 0){                                                     
 | |181             perror("send error");                                         
 | |182             return false;                                                 
 | |183         }                                                                 
 | |184         return true;                                                      
 | |185     }                                                                     
 | |186     bool Close(){                                                         
 | |187         close(_sockfd);                                                   
 | |188         _sockfd = -1;                                                     
 | |189     }                                                                     
 | |190 //    ~TcpSocket() {}                                                     
 | |191 private:                                                                  
 | |192     int _sockfd;                                                          
 | |193 }; 

Tcp_Server.cpp

1 /**********************************************************
  2  * Author        : yang
  3  * Email         : wk_eternity@163.com
  4  * Last modified : 2019-07-18 10:02
  5  * Filename      : Tcp_Server.cpp
  6  * Description   : 基于封装的tcpsocket完成tcp服务端程序pp
  7  *                  1.创建套接字
  8  *                  2.绑定地址信息
  9  *                  3.开始监听
 10  *                  4.获取已经连接成功的客户端socket
 11  *                  5.接受数据
 12  *                  6.发送数据
 13  *                  7.关闭套接字
 14  * *******************************************************/
 15 
 16 #include <iostream>
 17 #include "TcpSocket.hpp"
 18 
 19 int main(int argc,char *argv[])
 20 {
 21     if(argc != 3){
 22         printf("./tcp_srv ip port\n");
 23         return -1;
 24     }
 25     std::string ip = argv[1];
 26     uint16_t port = atoi(argv[2]);
 27 
 28     TcpSocket sock;
 29     CHECK_RET(sock.Socket());                                                                                                                                        
 30     CHECK_RET(sock.Bind(ip,port));
 31     CHECK_RET(sock.Listen());
 32 
 33     char buf[1024];
 34     while(1){
 35         TcpSocket clisock;
 36         struct sockaddr_in cliaddr;
 37         //accept是阻塞获取已经完成的连接                                      
 38         if (sock.Accept(clisock,&cliaddr) == false){
 39             continue;
 40         }
 41         printf("new connect client:%s:%d\n",inet_ntoa(cliaddr.sin_addr), ntohs
 42 
 43         int fd = clisock.GetSockFd();
 44         //calculator_info info;
 45         char buf[1024];
 46         while(1){
 47             fflush(stdout);
 48             //recv(fd, &info,sizeof(calculator_info),0);
 49             recv(fd, buf,sizeof(buf),0);
 50             //std::cout<<"clinet says:"<<info.str<<std::endl;
 51             std::cout<<"clinet says:"<<buf<<std::endl;
 52             //printf("num1:[%d] %c num2[%d] = [%d]\n",info.num1, info.op, info
 53 
 54             fflush(stdin);
 55             std::cin>>buf;
 56             send(fd, buf,sizeof(buf),0);
 57          }
 58     }
 59     sock.Close();
 60     return 0;
 61 }

Tcp_client.cpp

  1 /**********************************************************
  2  * Author        : yang
  3  * Email         : wk_eternity@163.com
  4  * Last modified : 2019-07-18 16:34
  5  * Filename      : Tcp_client.cpp
  6  * Description   : 使用封装的tcpsocket类实现tcp客户端程序
  7  *                  1.创建套接字
  8  *                  2.向服务端发起连接请求
  9  *                  3.发送数据
 10  *                  4.接受数据
 11  *                  5.关闭套接字
 12  * *******************************************************/
 13 #include <iostream>
 14 #include "TcpSocket.hpp"
 15 
 16 int main(int argc,char *argv[])
 17 {
 18     if(argc != 3){
 19         std::cout<<".tcp_cli ip port\n";
 20         return -1;
 21     }
 22     std::string ip = argv[1];
 23     uint16_t port = atoi(argv[2]);
 24 
 25     TcpSocket sock;
 26     CHECK_RET(sock.Socket());
 27     CHECK_RET(sock.Connect(ip, port));
 28 
 29     char buf[1024];
 30     while(1) {
 31         calculator_info info;
 32         info.num1 = 11;
 33         info.num2 = 12;
 34         info.op = '+';  
 35 
 36         //strcpy(info.str,"client 666");
 37         fflush(stdin);
 38         std::cin>>buf;
 39         int fd = sock.GetSockFd();
 40         send(fd, buf, sizeof(buf), 0);
 41 
 42         fflush(stdout);
 43         recv(fd, buf,sizeof(buf), 0);
 44         std::cout<<"server says:"<<buf<<std::endl;
 45     }
 46     sock.Close();
 47     return 0;
 48 }

执行结果:

[test@localhost my]$ ./Tcp_Server 127.0.0.1 10099
new connect client:127.0.0.1:51154
clinet says:1
2
clinet says:3
4
clinet says:5
6
clinet says:7

[test@localhost my]$ ./Tcp_client 127.0.0.1 10099
connect success
1
server says:2
3
server says:4
5
server says:6
7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值