一、函數(shù)說明
- 地址接口
1、通用地址接口
struct sockaddr
{
u_short sa_family; //地址類型,IPV4,用宏AG_INET即可;2字節(jié);
char sa_data[14]; //14字節(jié)的地址數(shù)據(jù);
};
共16字節(jié) = 2字節(jié)地址類型 + 14字節(jié)地址數(shù)據(jù)
2、自定義地址接口
struct sockaddr_in
{
short int sin_family; //地址族,IPv4,用宏AF_INET;
unsigned short int sin_port; //端口號,需要htons函數(shù)進(jìn)行字節(jié)序轉(zhuǎn)換;
struct in_addr sin_addr; //IP地址,需要inet_addr函數(shù)進(jìn)行轉(zhuǎn)換(點(diǎn)分字符串→數(shù)值),該成員本身也是一個結(jié)構(gòu)體;
unsigned char sin_zero[8]; //8個字節(jié)填0;
};
- 地址轉(zhuǎn)換
1、需要將點(diǎn)分字符串ip轉(zhuǎn)化為程序ip,使用inet_addr函數(shù):
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//inet_addr需要包含以上三個頭文件;
struct sockaddr_in servaddr; //先定義一個該種地址接口的結(jié)構(gòu)體變量;
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
2、字節(jié)序轉(zhuǎn)換
地址接口配置中的端口需要字節(jié)序轉(zhuǎn)換,網(wǎng)絡(luò)規(guī)定使用大端字節(jié)序。
#include <arpa/inet.h> //頭文件;
//從主機(jī)(h)發(fā)送到網(wǎng)絡(luò)(n):
// 把unsigned long類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
uint32_t htonl(uint32_t hostlong);
// 把unsigned short類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
uint16_t htons(uint16_t hostshort); //最常用!
//從網(wǎng)絡(luò)(n)接收到主機(jī)(h):
// 把unsigned long類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序
unit32_t ntohl(uint32_t netlong);
// 把unsigned short類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序
unit16_t ntohs(uint16_t netshort);
- 地址接口配置
1、socket:創(chuàng)建套接字
#include<sys/types.h>
#include<sys/socket.h>
int socket(int family, int type, int protocol);
參數(shù) | 含義 |
---|---|
family | 協(xié)議族,對于IPV4用宏AF_INET; |
type | 套接字類型:①對于tcp協(xié)議用宏SOCK_STREAM;②對于udp協(xié)議,用宏SOCK_DGRAM; |
protocol | 指定為0即可; |
返回值 | 成功:返回文件描述符;失敗:-1; |
2、bind:綁定
#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr* servaddr, socklen_t addrlen);
參數(shù) | 含義 |
---|---|
sockfd | 前面socket創(chuàng)建成功返回的套接字,即文件描述符; |
servaddr | 配置好的通用地址接口.配置好的地址接口,屬于struct sockaddr_in 類型,需要轉(zhuǎn)換成第一種通用地址接口;注意是socklen_t類型,可以提前定義一個socklen_t類型變量,然后讓其等于sizeof(servaddr) |
addrlen | 配合第二個參數(shù)共同確認(rèn)地址接口變量的內(nèi)容; |
返回值 | 成功:0;失敗:-1; |
3、地址接口初始化
bzero(&servaddr, sizeof(servaddr)); //將地址接口結(jié)構(gòu)體清空;
servaddr.sin_family = AF_INET; //用宏AF_INET代表IPV4;
servaddr.sin_port = htons(8080); //設(shè)置端口號(字節(jié)序轉(zhuǎn)換);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //這個宏表示任意IP地址,因?yàn)榉?wù)器不限定來訪的客戶端IP;
4、listen:監(jiān)聽(服務(wù)端專用)
#include<sys/types.h>
#include<sys/socket.h>
int listen(int sockfd, int backlog);
參數(shù) | 含義 |
---|---|
sockfd | socket創(chuàng)建套接字的返回值 |
backlog | 服務(wù)器的監(jiān)聽長度,設(shè)置1024即可 |
返回值 | 成功:0;失?。?1 |
5、accept:服務(wù)端連接
#include<sys/types.h>
#include<sys/socket.h>
int accept(int sockfd, struct sockaddr* cliaddr, socklen_t * addrlen);
參數(shù) | 含義 |
---|---|
sockfd | socket創(chuàng)建套接字的返回值 |
cliaddr | 是一個輸出參數(shù),從accept帶回來的的地址接口(客戶端),屬于struct sockaddr_in 類型,需要轉(zhuǎn)換成第一種通用地址接口 |
addrlen | 配合第二個參數(shù)共同確認(rèn)地址接口變量的內(nèi)容,取該變量的地址 |
返回值 | 成功:0;失敗:-1 |
6、connect:客戶端連接
#include<sys/types.h>
#include<sys/socket.h>
int connect(int sockfd, struct sockaddr* servaddr, socklen_t addrlen);
參數(shù) | 含義 |
---|---|
sockfd | socket創(chuàng)建套接字的返回值 |
servaddr | 配置好的地址接口,屬于struct sockaddr_in 類型,需要轉(zhuǎn)換成第一種通用地址接口 |
addrlen | 配合第二個參數(shù)共同確認(rèn)地址接口變量的內(nèi)容,注意不是地址,直接是該變量 |
返回值 | 成功:0;失?。?1 |
- 收發(fā)數(shù)據(jù)
1、read/write
因?yàn)閟ocket返回的是文件描述符,因此也可以像文件一樣使用read/write函數(shù)進(jìn)行數(shù)據(jù)傳輸。
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int write(int connfd, void* buff, size_t length);
int read(int connfd, void* buff, size_t length);
參數(shù) | 含義 |
---|---|
sockfd | socket創(chuàng)建套接字的返回值 |
buff | 文件緩沖區(qū),一般使用數(shù)組 |
length | 想要讀(收)、寫(發(fā))的字節(jié)數(shù),對于單獨(dú)數(shù)組:strlen(buff),對于結(jié)構(gòu)體數(shù)組:sizeof(node) |
返回值 | 成功:>0,實(shí)際發(fā)或者收到的字節(jié)數(shù);0:遇到文件尾巴;失?。?1 |
2、send/recv
#include<sys/types.h>
#include<sys/socket.h>
size_t send(int connfd, void* buff, size_t length, int flags);
size_t recv(int connfd, void* buff, size_t length, int flags);
flags功能選項(xiàng):
① 0:等同于write、read;
② MSG_DONTROUTE:send用,表示不查詢路由表,在內(nèi)部局域網(wǎng)進(jìn)行通信;
③ MSG_OOB:接收或發(fā)送帶外數(shù)據(jù)(插隊(duì));
④ MSG_PEEK:read用,表示讀取時不刪除數(shù)據(jù);
⑤ MSG_WAITALL:等待所有數(shù)據(jù)(阻塞等待);
返回值 :
成功:>0,實(shí)際發(fā)或者收到的字節(jié)數(shù);
0:對方已經(jīng)下線;
失?。?1;
二、示例代碼
客戶端client.cpp:文章來源:http://www.zghlxwxcb.cn/news/detail-829363.html
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
#define SIZE 1024
void connectToServer(int &serverfd){
char sendBuf[SIZE], recvBuf[SIZE];
ssize_t sendRet, recvRet;
while(1){
// 發(fā)送數(shù)據(jù)及接收響應(yīng)
cout << ">> ";
cin >> sendBuf;
while(sendBuf){
sendRet = send(serverfd, sendBuf, sizeof(sendBuf), 0);
if(strcmp(sendBuf, "$") == 0)
break;
if (sendRet == -1)
cout << "Error sending data\n";
else
cout << "Sent data: " << sendBuf << endl;
cout << ">> ";
cin >> sendBuf;
}
// 接收響應(yīng)及數(shù)據(jù)
recvRet = recv(serverfd, recvBuf, sizeof(recvBuf), 0);
while(recvRet > 0){
recvBuf[recvRet] = '\0';
if(strcmp(recvBuf, "$") == 0)
break;
cout << "Received data: " << recvBuf << endl;
recvRet = recv(serverfd, recvBuf, sizeof(recvBuf), 0);
}
// 是否關(guān)閉連接
cout << "Do you want to close connection? (y/n)";
char c;
while ((c = getchar()) != '\n' && c != EOF);
cin >> sendBuf;
while(strcmp(sendBuf, "y") !=0 && strcmp(sendBuf, "n") != 0){
cout << "Wrong input! Please input a letter 'y' or 'n' : ";
cin >> sendBuf;
}
sendRet = send(serverfd, sendBuf, sizeof(sendBuf), 0);
if (sendRet == -1)
cout << "Error sending data\n";
if(strcmp(sendBuf, "y") == 0)
break;
}
// 關(guān)閉套接字
close(serverfd);
}
int main() {
// 創(chuàng)建套接字
int serverfd = socket(AF_INET, SOCK_STREAM, 0);
if (serverfd == -1) {
cerr << "Error creating socket\n";
return 1;
}
// 連接到服務(wù)器
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080); // 與服務(wù)器相同的端口號
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr); // 這里使用本地回環(huán)地址,如果服務(wù)器在另一臺機(jī)器上,請?zhí)鎿Q為服務(wù)器的IP地址
if (connect(serverfd, reinterpret_cast<struct sockaddr*>(&serverAddr), sizeof(serverAddr)) != -1) {
cout << serverfd << " : Connected successfully!" << endl;
connectToServer(serverfd);
} else {
cerr << "Error connecting to server\n";
close(serverfd);
return 1;
}
return 0;
}
服務(wù)端server.cpp:文章來源地址http://www.zghlxwxcb.cn/news/detail-829363.html
- 一對一通信
#include <iostream>
using namespace std;
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define SIZE 1024
void connectToClient(int &clientfd) {
char recvBuf[SIZE]; // 接收緩沖區(qū)
char sendBuf[SIZE]; // 發(fā)送緩沖區(qū)
int recvRet, sendRet; // 接受反饋及發(fā)送反饋
while (clientfd != -1) {
// receive data
recvRet = recv(clientfd, recvBuf, sizeof(recvBuf), 0);
while(recvRet > 0) {
recvBuf[recvRet] = '\0';
if(strcmp(recvBuf, "$") == 0)
break;
cout << "recv data from client " << clientfd << ", data : " << recvBuf << endl;
recvRet = recv(clientfd, recvBuf, sizeof(recvBuf), 0);
}
// send data
cout << clientfd << ">> ";
cin >> sendBuf;
while(sendBuf) {
sendRet = send(clientfd, sendBuf, sizeof(sendBuf), 0);
if (strcmp(sendBuf, "$") == 0)
break;
if (sendRet == -1)
cout <<"send data error." << endl;
else
cout << "Sent data to client: " << sendBuf << endl;
cout << clientfd << ">> ";
cin >> sendBuf;
}
// 是否關(guān)閉連接
recvRet = recv(clientfd, recvBuf, sizeof(recvBuf), 0);
if (recvRet == -1)
cout << "Error receiving data\n";
else if(strcmp(recvBuf, "y") == 0) {
cout << "Have closed connection " << clientfd << '.' << endl;
close(clientfd);
break;
}
}
}
int main() {
// create socket
int serverfd = socket(AF_INET, SOCK_STREAM, 0); // IPV4 + TCP
if(-1 == serverfd) {
printf("create socket error");
return -1;
}
// bind port
struct sockaddr_in bindaddr;
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindaddr.sin_port = htons(8080);
if(-1 == bind(serverfd, (struct sockaddr *)&bindaddr, sizeof(bindaddr))) {
cout << "bind error" << endl;
return -1;
}
// start listen
if (listen(serverfd, 1024) == -1) {
printf("listem error");
return -1;
}
while (1) {
struct sockaddr_in clientaddr;
socklen_t clientaddrlen = sizeof(clientaddr);
// accept connection
int clientfd = accept(serverfd, (struct sockaddr *)&clientaddr, &clientaddrlen);
if(clientfd!= -1) {
// 獲取客戶端的信息
char cliIp[16];
inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, cliIp, sizeof(cliIp));
unsigned short cliPort = ntohs(clientaddr.sin_port);
cout << "client ip is : " << cliIp << ", port is : " << cliPort << endl;
connectToClient(clientfd);
}
}
//close socket
close(serverfd);
return 0;
}
- 一對多通信(多進(jìn)程)
#include <iostream>
using namespace std;
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define SIZE 1024
void connectToClient(int &clientfd) {
char recvBuf[SIZE]; // 接收緩沖區(qū)
char sendBuf[SIZE]; // 發(fā)送緩沖區(qū)
int recvRet, sendRet; // 接受反饋及發(fā)送反饋
while (clientfd != -1) {
// receive data
recvRet = recv(clientfd, recvBuf, sizeof(recvBuf), 0);
while(recvRet > 0) {
recvBuf[recvRet] = '\0';
if(strcmp(recvBuf, "$") == 0)
break;
cout << "recv data from client " << clientfd << ", data : " << recvBuf << endl;
recvRet = recv(clientfd, recvBuf, sizeof(recvBuf), 0);
}
// send data
cout << clientfd << ">> ";
cin >> sendBuf;
while(sendBuf) {
sendRet = send(clientfd, sendBuf, sizeof(sendBuf), 0);
if (strcmp(sendBuf, "$") == 0)
break;
if (sendRet == -1)
cout <<"send data error." << endl;
else
cout << "Sent data to client: " << sendBuf << endl;
cout << clientfd << ">> ";
cin >> sendBuf;
}
// 是否關(guān)閉連接
recvRet = recv(clientfd, recvBuf, sizeof(recvBuf), 0);
if (recvRet == -1)
cout << "Error receiving data\n";
else if(strcmp(recvBuf, "y") == 0) {
cout << "Have closed connection " << clientfd << '.' << endl;
close(clientfd);
break;
}
}
}
int main() {
// create socket
int serverfd = socket(AF_INET, SOCK_STREAM, 0); // IPV4 + TCP
if(-1 == serverfd) {
printf("create socket error");
return -1;
}
// bind port
struct sockaddr_in bindaddr;
bindaddr.sin_family = AF_INET;
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bindaddr.sin_port = htons(8080);
if(-1 == bind(serverfd, (struct sockaddr *)&bindaddr, sizeof(bindaddr))) {
cout << "bind error" << endl;
return -1;
}
// start listen
if (listen(serverfd, 1024) == -1) {
printf("listem error");
return -1;
}
while (1) {
struct sockaddr_in clientaddr;
socklen_t clientaddrlen = sizeof(clientaddr);
// accept connection
int clientfd = accept(serverfd, (struct sockaddr *)&clientaddr, &clientaddrlen);
if(clientfd!= -1) {
// 獲取客戶端的信息
char cliIp[16];
inet_ntop(AF_INET, &clientaddr.sin_addr.s_addr, cliIp, sizeof(cliIp));
unsigned short cliPort = ntohs(clientaddr.sin_port);
cout << "client ip is : " << cliIp << ", port is : " << cliPort << endl;
pid_t pid = fork();
if(pid == 0) // 子進(jìn)程
connectToClient(clientfd);
}
}
//close socket
close(serverfd);
return 0;
}
到了這里,關(guān)于Linux網(wǎng)絡(luò)編程——C++實(shí)現(xiàn)進(jìn)程間TCP/IP通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!