c++ socket 通讯的简单实现

socket

socket 就是TCP/IP的抽象层,当我们使用 socket 编程时,可以不用担心TCP/IP协议簇的实现过程。

c++ 中相关的结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct sockaddr {
unsigned short sa_family;
char sa_data[14]; // 14字节协议地址
};
/* Internet 地址 (一个与历史有关的结构) */
struct in_addr {
unsigned long s_addr;
};
// 主要用到下面这个
struct sockaddr_in {
short int sin_family; // 通信类型
unsigned short int sin_port; // 端口
struct in_addr sin_addr; // Internet 地址
unsigned char sin_zero[8]; // 与sockaddr结构的长度相同
};

在 Linux 下,用到的头文件有:

1
2
3
4
//头文件
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

主要函数

socket()

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

domain 应该设置成 “AF_INET”,就 象上面的数据结构struct sockaddr_in 中一样。然后,参数 type 告诉内核是 SOCK_STREAM 类型还是 SOCK_DGRAM 类型。最后,把 protocol 设置为 “0”。函数会返回一个sfd 套接字描述符

bind()

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

将套接字和机器端口关联起来

listen()

int listen(int sockfd, int backlog)

监听端口函数。sockfd 是调用 socket() 返回的套接字文件描述符。backlog是在进入 队列中允许的连接数目。

accept()

int accpet(int sockfd, void *addr, int *addrlen)

server从等待队列中取出套接字描述符,用于发送和接受数据。

connect()

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)

sockfd 是系统调用 socket() 返回的套接字文件描述符。serv_addr 是 保存着目的地端口和 IP 地址的数据结构 struct sockaddr。错误的时候返回-1,并 设置全局错误变量 errno。

send()

int send(int sockfd, const void *msg, int len, int flags)

发送数据函数,sockfd 是你想发送数据的套接字描述符(或者是调用 socket() 或者是 accept() 返回的。)msg 是指向你想发送的数据的指针。len 是数据的长度。 把 flags 设置为 0 。

recv()

int recv(int sockfd, void *buf, int len, unsigned int flags)

将接受到的数据赋值到buf这个变量

shutdown()

int shutdown(int sockfd, int how)

sockfd 是你想要关闭的套接字文件描述复。how 的值是下面的其中之 一: 0或SHUT_RD – 不允许接收 1或SHUT_WR – 不允许发送 2或SHUT_RDWR – 不允许发送和接收(和 close() 一样)

代码

server.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
// #include <winsock.h>
#include <arpa/inet.h>
#include <cstring>
#define PORT 8888
using namespace std;
class Server
{
private:
int port;
int sfd;
int cfd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t c_len;
public:
Server(int port = PORT) // construct
{
// int socket(int domain, int type, int protocol);
sfd = socket(AF_INET, SOCK_STREAM,0);
if (sfd == -1) {
throw("create fail\n");
}
cout << "create successfully\n";
server_addr.sin_family = AF_INET; // 定义server信息
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 4字节的 IP 地址转换
// int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
bind(sfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
// int listen(int sockfd, int backlog); // backlog 进入队列中允许的连接数
listen(sfd, 20);
}
void run()
{
int rec_len = 0;
char buffer[1024] = {0};
// int c_len = sizeof(sockaddr_in);
cfd = accept(sfd, (struct sockaddr*)&client_addr, &c_len); // 获取等待连接
while(1) {
rec_len = recv(cfd, buffer, sizeof(buffer), 0);
cout <<"get Buffer\n";
cout << buffer <<endl;
send(cfd, buffer, strlen(buffer), 0);
memset(buffer, 0, sizeof(buffer)); // 清楚buffer变量内存内容
}
}
};
int main()
{
Server *s = NULL;
s = new Server;
s->run();
return 0;
}

client.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
// #include <winsock.h>
#include <arpa/inet.h>
#include <cstring>
#define PORT 8888
using namespace std;
class Server
{
private:
int port;
int sfd;
int cfd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t c_len;
public:
Server(int port = PORT) // construct
{
// int socket(int domain, int type, int protocol);
sfd = socket(AF_INET, SOCK_STREAM,0);
if (sfd == -1) {
throw("create fail\n");
}
cout << "create successfully\n";
server_addr.sin_family = AF_INET; // 定义server信息
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 4字节的 IP 地址转换
// int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
bind(sfd,(struct sockaddr*)&server_addr,sizeof(server_addr));
// int listen(int sockfd, int backlog); // backlog 进入队列中允许的连接数
listen(sfd, 20);
}
void run()
{
int rec_len = 0;
char buffer[1024] = {0};
cfd = accept(sfd, (struct sockaddr*)&client_addr, &c_len); // 获取等待连接
while(1) {
rec_len = recv(cfd, buffer, sizeof(buffer), 0);
cout <<"get Buffer\n";
cout << buffer <<endl;
send(cfd, buffer, strlen(buffer), 0);
memset(buffer, 0, sizeof(buffer)); // 清楚buffer变量内存内容
}
}
};
int main()
{
Server *s = NULL;
s = new Server;
s->run();
return 0;
}