概念圖
?創(chuàng)建服務(wù)器讓A,B主機(jī)完成通信。
認(rèn)識(shí)接口
socket
?返回值:套接字,你可以認(rèn)為類似fd
參數(shù):
- domain->:哪種套接字,常用AF_INET(網(wǎng)絡(luò)套接字)、AF_LOCAL(本地套接字)
- type->:發(fā)送數(shù)據(jù)類型,常用?SOCK_DGRAM(以數(shù)據(jù)報(bào)式發(fā)送)
- protocol->:一般填0,自動(dòng)推導(dǎo)類型或者IPPROTO_UDP、IPPROTO_TCP。
創(chuàng)建一個(gè)套接字,類似創(chuàng)建一個(gè)文件標(biāo)識(shí)符fd。
先介紹些結(jié)構(gòu)體類型
struct sockaddr
struct sockaddr_in
struct sockaddr_un
_in結(jié)構(gòu)體中保存的是ip\port數(shù)據(jù),而_un中保存的則是本地的數(shù)據(jù)
udp協(xié)議為了本地通信與網(wǎng)絡(luò)通信同一套接口兼容,所以先將sockaddr_in/_un強(qiáng)轉(zhuǎn)成sockaddr類型傳入各個(gè)函數(shù),在函數(shù)中判斷前2個(gè)字節(jié)類型,來(lái)做本地通信或者網(wǎng)絡(luò)通信。
bind
將套接字綁定,一般來(lái)說套接字綁定都是服務(wù)器才會(huì)綁定的,客戶端一般給操作系統(tǒng)自動(dòng)分配ip與端口的。
返回值:成功0,失敗-1.設(shè)置錯(cuò)誤碼
參數(shù):
- sockfd 需要綁定的套接字
- sockaddr包含了需要與套接字綁定的ip和端口號(hào)。
- addrlen該結(jié)構(gòu)體長(zhǎng)度。
recvfrom
用來(lái)接收數(shù)據(jù)的接收
返回值:實(shí)際接收數(shù)據(jù)的長(zhǎng)度,-1失敗
參數(shù)
- sockfd:將從該套接字的端口和ip中取得數(shù)據(jù)
- buff:輸出型參數(shù),將數(shù)據(jù)存放到buff中。
- len:buff的長(zhǎng)度
- flags:以狀態(tài)等待數(shù)據(jù),一般填0,阻塞等待數(shù)據(jù)
- src_addr:發(fā)送方ip+port結(jié)構(gòu)體數(shù)據(jù),輸出型參數(shù)
- 結(jié)構(gòu)體數(shù)據(jù)長(zhǎng)度
sendto
發(fā)送數(shù)據(jù)給某個(gè)主機(jī)
返回值:實(shí)際發(fā)送數(shù)據(jù)的個(gè)數(shù),-1失敗
參數(shù)
- sockfd:將發(fā)送方的ip+port發(fā)送給對(duì)方
- buff:輸入型參數(shù),將buff中數(shù)據(jù)發(fā)送給對(duì)方。
- len:buff的長(zhǎng)度;
- flags:默認(rèn)發(fā)送方式發(fā)送
- 接收方ip+port結(jié)構(gòu)體數(shù)據(jù),根據(jù)該參數(shù)尋找對(duì)于主機(jī)
- 結(jié)構(gòu)體數(shù)據(jù)長(zhǎng)度
sockaddr_in結(jié)構(gòu)體配套函數(shù)
機(jī)器大小端的轉(zhuǎn)換函數(shù)。h本地to轉(zhuǎn)
以太網(wǎng)規(guī)定,網(wǎng)絡(luò)傳輸數(shù)據(jù)一定是大端方式傳輸,所以我們的機(jī)器無(wú)論是大端還是小端,在網(wǎng)絡(luò)中都會(huì)成為大端序列。
?當(dāng)是為了人能看的明白,我們的ip地址一般都是以字符串的方式呈現(xiàn),這樣的方式我們稱為點(diǎn)分十進(jìn)制的方式。而且傳入為了的ip地址可能需要改序列,所以一批接口出現(xiàn)了。
這些接口將字符串轉(zhuǎn)為uint32_t或者將uint32_t轉(zhuǎn)為字符串
代碼
一份2個(gè)主機(jī)通過服務(wù)器可以聊天的代碼
服務(wù)器代碼:
server.hpp
#pragma once
#include <cstdio>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include <unordered_map>
using std::cin;
using std::cout;
using std::endl;
class udp_server
{
typedef int socket_t;
void ip_type()
{
cout << "ip:" << _ip << endl;
if (_ip == "127.0.0.1")
{
cout << "#####本地測(cè)試#####" << endl;
}
else if (_ip.empty())
{
cout << "#####開放全部ip地址#####" << endl;
}
else
{
cout << "#####指定ip地址#####" << endl;
}
}
void init_server()
{
_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (_socket < 0)
{
Log(FATAL, "socket get fail!!![%d][%s]\n", __LINE__, __TIME__);
exit(1);
}
struct sockaddr_in ip_port;
bzero(&ip_port, sizeof(ip_port));
ip_port.sin_family = AF_INET;
ip_port.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
ip_port.sin_port = htons(_port);
if (bind(_socket, (struct sockaddr *)&ip_port, sizeof(ip_port)) < 0)
{
Log(FATAL, "bind fail!!![%d][%s]\n", __LINE__, __TIME__);
exit(2);
}
Log(NORMAL, "udp init success!!![%d][%s]\n", __LINE__, __TIME__);
}
public:
udp_server(uint16_t port, std::string ip = "") : _ip(ip), _port(port) {}
udp_server() {}
void activate()
{
init_server();
ip_type();
while (1)
{
char buff[1024] = {0};
// cout<<"buff size: "<<strlen(buff)<<endl;
struct sockaddr_in client_ip_port;
socklen_t len = sizeof(client_ip_port);
//開始等待客戶端
ssize_t end = recvfrom(_socket, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&client_ip_port, &len);
char retbuff[1024]={0};
// cout<<"buff size: "<<strlen(buff)<<endl;
if (end >= 0)
{
buff[end] = '\0';
printf("[%s:%d]clint say# %s\n", inet_ntoa(client_ip_port.sin_addr), ntohs(client_ip_port.sin_port), buff);
sprintf(retbuff,"[%s:%d]clint say# %s", inet_ntoa(client_ip_port.sin_addr), ntohs(client_ip_port.sin_port), buff);
}
else
{
Log(WARINNG, "recvfrom Message have fail [%d][%s]\n", __LINE__, __TIME__);
}
//處理數(shù)據(jù)。
char key[64];
snprintf(key,sizeof(key),"%s-%u",inet_ntoa(client_ip_port.sin_addr),client_ip_port.sin_port);
auto it = _users.find(key);
if(it==_users.end())
{
cout<<key<<endl;
cout<<key<<" :放入客戶端"<<endl;
_users.insert({key,client_ip_port});
}
// cout<<"end : "<<end<<endl;
//反饋
for(auto&it:_users)
{
if(client_ip_port.sin_addr.s_addr==it.second.sin_addr.s_addr)
{
continue;
}
sendto(_socket, retbuff, sizeof retbuff, 0, (struct sockaddr *)&(it.second), sizeof(it.second));
}
Log(Debug, "sendto Message have fail [%d][%s]\n", __LINE__, __TIME__);
}
}
private:
socket_t _socket;
std::string _ip;
uint16_t _port;
std::unordered_map<std::string, struct sockaddr_in> _users;
};
server.cpp文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-688940.html
#include "server.hpp"
#include <memory>
using std::shared_ptr;
void SERVERUER()
{
std::cout<<"./server + ip + port"<<std::endl;
}
int main(int argc,char*argv[])
{
if(argc==2||argc==3)
{
cout<<"argc:"<<argc<<endl;
if(argc==2)
{
in_port_t port=atoi(argv[1]);
shared_ptr<udp_server> server_ptr(new udp_server(port));
server_ptr->activate();
}
else
{
in_port_t port=atoi(argv[2]);
std::string ip=argv[1];
shared_ptr<udp_server> server_ptr(new udp_server(port,ip));
server_ptr->activate();
}
}
else
{
SERVERUER();
}
return 0;
}
客戶端代碼
client.cpp文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-688940.html
#include <cstdio>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include <pthread.h>
using std::cin;
using std::cout;
using std::endl;
typedef int socket_t;
void CLIENTUER()
{
std::cout << "./client + ip + port" << std::endl;
}
void *thread_func(void *ages)
{
socket_t *_socket = (socket_t*)ages;
char get_messages[102];
struct sockaddr_in temp;
bzero((void *)&temp, sizeof(temp));
socklen_t len(sizeof temp);
while (1)
{
ssize_t end = recvfrom(*_socket, get_messages, sizeof(get_messages) - 1, 0, (struct sockaddr *)&temp, &len);
if (end >= 0)
{
get_messages[end] = 0;
std::cout<< get_messages << std::endl;
}
}
return nullptr;
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
CLIENTUER();
exit(1);
}
socket_t _socket = socket(AF_INET, SOCK_DGRAM, 0);
pthread_t tid;
pthread_create(&tid,nullptr,thread_func,(void*)&_socket);
std::string messages;
struct sockaddr_in server_ip_port;
bzero(&server_ip_port, sizeof(server_ip_port));
server_ip_port.sin_family = AF_INET;
server_ip_port.sin_addr.s_addr = inet_addr(argv[1]);
server_ip_port.sin_port = htons(atoi(argv[2]));
socklen_t len = sizeof(server_ip_port);
while (1)
{
fflush(stdout);
std::getline(std::cin, messages);
sendto(_socket, messages.c_str(), messages.size(), 0, (struct sockaddr *)&server_ip_port, len);
}
return 0;
}
到了這里,關(guān)于以u(píng)dp協(xié)議創(chuàng)建通信服務(wù)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!