作者:小 琛
欢迎转载,请标明出处
socket_tcp编程流程
为什么要新创建socket来进行通信?
在tcp通信中,往往为客户端真正服务的是新创建的出来的socket,而最初连接用的socket实际是监听作用。这样做的原因是当已经有一个连接且在通信时,仍然允许新的客户端连接。
函数接口
创建套接字的接口
int socket(int domain, int type, int protocol)
参数:
domain:地址域,传入协议的版本。针对于网络层的参数。
AF_INET:ipv4版本协议 AF_INET6: IPV6版本协议
type:套接字的类型。针对传输层的参数
SOCK_STREAM::流式套接字;协议默认tcp,不支持udp
SOCK_DGRAM::数据报套接字;默认协议为udp,不支持tcp
protocol:协议
0:采用套接字默认协议
IPPROTO_TCP(或6):tcp协议
IPPROTO_UDP(或17):udp协议
返回值:套接字的操作句柄,本质为一个文件描述符,通常称之为套接字描述符。
绑定地址信息接口
int bind (int sockfd, const struct sockaddr* addr, socklen_t addrlen)
参数:
sockfd:套接字操作句柄
addr:为更好的兼容不同协议的地址信息而设定的结构体
struct sockaddr_in
{
sin_family;//告诉内核以何种协议去解析,例如传AF_INET即ipv4
sin_port;端口信息
sin_addr.s_addr;uint32_t类型的ip地址
}
注意:我们通常使用上述结构体,但和参数类型并不匹配,因此该参数需要进行强转,否则会报错;(struct sockte_addr*)&addr。
addrlen:地址信息长度
监听:
int listen(int sockfd, int backlog )
- 参数:
sockfd:套接字描述符
backlog:已完成连接队列的大小。可以指定大小,若当前队列已满,会丢弃新来的连接,从以完成连接队列中获取创建完成的新连接- 返回值:
失败返回-1,否则返回1
3.监听状态
已完成连接队列:三次握手完成的连接集合
未完成连接队列:处于三次握手当中的连接集合
获取连接
int accept (int sockfd, struct sockaddr* addr,socklen_t addrlen)
- 参数
sockfd:侦听套接字描述符
addr:客户端的地址信息
addrlen:客户端地址信息长度- 返回值
返回新创建出来socket的sockfd,通过新创建出来的socket为客户端服务。- 注意
该接口是从已完成连接的队列中获取连接,因此当已完成队列中没有新的连接时候,会阻塞,知道获取新的连接
发送连接
int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen)
- 参数
sockfd:套接字描述符
addr:服务端地址信息,需要在代码中配置
addrlen:地址信息长度- 返回值
失败返回-1,否则为1
发送数据
sszie_t send(int sockfd, const void* buf, size_t len, int flags)
- 参数
sockfd:套接字描述符,要使用accept的返回值
buf:要发送的数据
len:发送的数据长度
flags:发送方式,0为阻塞发送- 返回值:
大于0:发送数据的长度
等于0:标识对端关闭了连接
小于0:失败
接收数据
ssize_t recv(int sockfd, void* buf, size_t len, int flags)
- 参数
sockfd:套接字描述符,要使用accept的返回值
buf:接收数据的存放
len:最大接收长度
flags:接收方式,0为阻塞接收,MSG_PEEK为探测接收- 返回值
大于0:发送数据的长度
等于0:标识对端关闭了连接
小于0:失败
关闭套接字
close(int sockfd)
tcp通信demo
- tcpsvr.hpp
1 #pragma once
2
3 #include <cstring>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <sys/socket.h>
7 #include <stdlib.h>
8 #include <iostream>
9 #include <string>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12
13 class TcpSvr
14 {
15 public:
16 TcpSvr()
17 {
18 _sockfd=-1;
19 }
20 ~TcpSvr()
21 {}
22 //1.创建套接字
23 bool CreatSocket()
24 {
25 _sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
26 if (_sockfd < 0)
27 {
28 perror("socket");
29 return false;
30 }
31 return true;
32 }
33 //2.绑定地址信息
34 bool Bind(std::string& ip,uint16_t port)
35 {
36 struct sockaddr_in addr;
37 addr.sin_family=AF_INET;
38 addr.sin_port=htons(port);
39 addr.sin_addr.s_addr=inet_addr(ip.c_str());
40 int ret=bind(_sockfd,(struct sockaddr*)&addr,sizeof(addr));
41 if (ret < 0)
42 {
43 perror("bind");
44 return false;
45 }
46 return true;
47 }
48 // 3.侦听
49 bool Listen(int n=5)
50 {
51 int ret=listen(_sockfd,n);
52 if (ret < 0)
53 {
54 perror("listen");
55 return false;
56 }
57 return true;
58 }
59 //4.获取连接
60 bool Accept(struct sockaddr_in* addr,TcpSvr* ts)
61 {
62 socklen_t socklen=sizeof(struct sockaddr_in);
63 int serverfd=accept(_sockfd,(struct sockaddr*)addr,&socklen);
64 if (serverfd < 0)
65 {
66 perror("accept");
67 return false;
68 }
69 ts->_sockfd=serverfd;
70 return true;
71 }
72 //5.发起连接
73 bool Connect(std::string& ip,uint16_t port)
74 {
75 struct sockaddr_in addr;
76 addr.sin_family=AF_INET;
77 addr.sin_port=htons(port);
78 addr.sin_addr.s_addr=inet_addr(ip.c_str());
79 int ret =connect(_sockfd,(struct sockaddr*)&addr,sizeof(addr));
80 if (ret < 0)
81 {
82 perror("connect");
83 return false;
84 }
85 return true;
86 }
87 //6.发送数据
88 bool Send(std::string& data)
89 {
90 int sendszie=send(_sockfd,data.c_str(),data.size(),0);
91 if (sendszie < 0)
92 {
93 perror("send");
94 return false;
95 }
96 return true;
97 }
98 //7.接收数据
99 bool Recv(std::string* buff)
100 {
101 char buf[1024];
102 memset(buf,'\0',sizeof(buf));
103 int recvsize=recv(_sockfd,buf,sizeof(buf)-1,0);
104 if (recvsize < 0)
105 {
106 perror("recv");
107 return false;
108 }
109 else if (recvsize == 0)//断开连接
110 {
111 printf("The connection has been disconnected\n");
112 return false;
113 }
114 else
115 {
116 (*buff).assign(buf,recvsize);
117 return true;
118 }
119 }
120 //8.关闭
121 void Close()
122 {
123 close(_sockfd);
124 _sockfd=-1;
125 }
126 private:
127 int _sockfd;
128 };
- cli.cpp
1 #include "tcpsvr.hpp"
2
3 int main(int argc,char* argv[])
4 {
5 if (argc!=3)
6 {
7 printf("Start Client: ./cli [server ip] [server port]\n");
8 return 0;
9 }
10 std::string ip=argv[1];
11 uint16_t port=atoi(argv[2]);
12
13 TcpSvr us;
14 if (!us.CreatSocket())
15 {
16 return 0;
17 }
18 if (!us.Connect(ip,port))
19 {
20 return 0;
21 }
22 while (1)
23 {
24 printf("please enter :");
25 fflush(stdout);
26 std::string buf;
27 std::cin >> buf;
28 us.Send(buf);
29
30 us.Recv(&buf);
31 printf("I get :%s\n",buf.c_str());
32 }
33 us.Close();
34 return 0;
35 }
- svr.cpp
1 #include "tcpsvr.hpp"
2
3 int main(int argc,char* argv[])
4 {
5 if (argc != 3)
6 {
7 printf("Start Server: ./svr [ip] [port]\n");
8 return 0;
9 }
10 std::string ip=argv[1];
11 uint16_t port=atoi(argv[2]);
12
13 TcpSvr us;
14 if (! us.CreatSocket())
15 {
16 return 0;
17 }
18 if (! us.Bind(ip,port))
19 {
20 return 0;
21 }
22 if (! us.Listen(5))
23 {
24 return 0;
25 }
26
27 TcpSvr sursock;
28 while (1)
29 {
30 struct sockaddr_in clientaddr;
31 if (! us.Accept(&clientaddr,&sursock))
32 {
33 return 0;
34 }
35
36 std::string buff;
37 sursock.Recv(&buff);
38 printf("I get:%s\n",buff.c_str());
39
40 printf("please enter :");
41 fflush(stdout);
42 std::cin>>buff;
43 sursock.Send(buff);
44 }
45 us.Close();
46 sursock.Close();
47 return 0;
48 }