赞
踩
数据有IP(公网)标识一台唯一的主机。
为了更好的标识一台主机上服务进程的唯一性,我们采用端口号port,标识服务器进程,客户端进程的唯一性!
IP地址(主机全网唯一性) + 该主机上的端口号,标识该服务器上进程的唯一性
ipA + portA, ipB + portB
相当于一个服务端进程 与一个客户端进程 通过网络资源来进行通信
1. 需要让不同的进程,先看到同一份资源 -- 网络
2. 通信不就是在做IO吗? -- 所以,我们所有的上网行为,无外乎两种:
a. 我要把我的数据发出去。
b. 我要收到别人给我发的数据。
a. 系统是系统,网络是网络,单独设置 -- 系统与网络解耦
b. 需要客户端每次都能找到服务器进程 -- 服务器的唯一性不能做任何改变 -- IP+port 不能随便改变 <-- 不能使用轻易会改变的值(pid每次进程启动会改变)
c. 不是所有的进程都要提供网络服务请求,但是所有的进程都需要pid
1. 传输层协议
2. 无连接
3. 不可靠传输
4. 面向数据报
可靠与不可靠是中性词。
可靠是有成本的。往往是比较复杂的,维护成本和编码成本比较高。
不可靠比较简单,维护成本和编码成本比较低。
TCP:银行系统、搜索引擎等;
UDP:推送广告等;
由于在同一台主机上的数据一般不是大端就是小端,我们不需要特别的注意。但是当两台主机通过网络发送和接受数据的时候,这个问题就要考虑起来,因此我们规定网络中的数据都是大端!当前发送主机是小端,就需要先将数据转成大端,否则就忽略,直接发送即可。
- uint32_t htonl(unit32_t hostlong);
- uint16_t htons(uint16_t hostshort);
- uint32_t ntohl(uint32_t netlong);
- uint16_t ntohs(uint16_t netshort);
ip+port就是套接字
1. 网络套接字
2. 原始套接字
3. unix域间套接字 (只能本地通信)
通过 struct sockaddr{}
这一套结构体可以分别表示网络通信和本地通信。根据第一个参数传入的是AF_INET还是AF_UNIX来内部判断
- #include <sys/types.h>
- #include <sys/socket.h>
-
- int socket(int domain,int type,int protocol);
AF_UNIX: 域间通信(本地通信)
AF_INET: 网络通信 (也可以是PF_INET)
SOCK_DGRAM: 数据报套接字 -- (对应的UDP)
SOCK_STREAM: 流式套接字 -- (对应的TCP)
未来我们想使用什么协议(指明是TCP协议还是UDP协议)
可以缺省为0 (前两个参数确定之后就可以确定是使用TCP还是UDP了不需要再传入第三个参数了)
文件描述符
- #include <sys/types.h>
- #include <sys/socket.h>
-
- int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
让OS知道我们的IP地址和端口号
创建套接字的返回值
含有 IP地址和端口号属性的结构体,我们通过该结构体将这两个属性传入进去
传入结构体的长度
绑定成功返回0
绑定失败返回-1
uint16_t sin_port;
struct in_addr sin_addr;
“124.223.97.182” -- > 点分十进制风格的IP,字符串,可读性好
uint32_t ip:整数风格的IP - 网络通信使用
uint32_t ip=12345;
struct _ip
{
unsigned char p1;
unsigned char p2;
unsigned char p3;
unsigned char p4;
};str_ip=
to_string(((struct _ip)&ip)->p1)+"."
to_string(((struct _ip)&ip)->p2)+"."
to_string(((struct _ip)&ip)->p3)+"."
to_string(((struct _ip)&ip)->p4);
系统接口可以直接对点分十进制和uint32_t类型的IP地址进行互相转换。
- #include<cstrings>
-
- void bzero(void *s, size_t n);
作用:初始化结构体类型的对象。
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-
- in_addr_t inet_addr(const char *cp);
1. string -> uint32_t
2. htonl();
一般情况下我们的服务器不指明一个特定的IP,一般会设置成INADDR_ANY。
任意地址bind,这样的话就不会错过其他不同的IP但是端口号与我们的服务器匹配的网络。
- struct sockaddr_in local; // 定义一个sockaddr_in的结构体
- local.sin_addr.s_addr = INADDR_ANY; // 不指名特定的一个IP
- #include <sys/types.h>
- #include <sys/socket.h>
-
- ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,struct sockaddr *src_addr, socklen_t *addrlen);
设置为0 为阻塞式读取
所传的结构体
所传的结构体长度
读取成功返回读取到的字符数。
读取失败返回-1。
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-
- char *inet_ntoa(struct in_addr in);
1. 将网络序列转换为主机序列
2. 并且将int转为点分十进制
因为写服务器的是一家公司,但是写客户端的是无数家公司。如果我们在客户端上绑定了特定的端口号,如果刚好这个端口号被别人占用了,那么就无法与服务器正常通信了。因此服务端是一定要我们手动去bind特定的端口号的,为了服务端端口号的唯一。客户端的端口号我们让OS自动形成就可以了。
- #include <sys/types.h>
- #include <sys/socket.h>
-
- ssize_t sendto(int sockfd, const void *buf,size_t len,int flags,const struct sockaddr *dest_addr,socklen_t addrlen);
要发送的缓冲区
缓冲区长度
客户端发数据,服务端接收数据。
- // 1. 套接字的创建
- _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (_sockfd == -1)
- {
- cerr << "socket error :" << errno << " : " << strerror(errno) << endl;
- exit(SOCKET_ERR);
- }
- cout << "socket success : " << _sockfd << endl;
- // 2. bind
- struct sockaddr_in local;
- bzero(&local, sizeof(local)); // 初始化local
-
- local.sin_family = AF_INET;
-
- // 1. 主机转网络 点分十进制转int
- local.sin_addr.s_addr = inet_addr(_serverip.c_str());
- // local.sin_addr.s_addr = INADDR_ANY;
- local.sin_port = htons(_serverport);
- int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
-
- if (n == -1)
- {
- cerr << "bind error: " << errno << " : " << strerror(errno) << endl;
- exit(BIND_ERR);
- }

- char buffer[NUM];
- for (;;)
- {
- struct sockaddr_in peer;
- socklen_t len = sizeof(peer);
- //
- ssize_t s = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
-
- if (s > 0)
- {
- // 读取数据
- buffer[s] = 0;
- uint16_t clientport = ntohs(peer.sin_port);
- string clientip = inet_ntoa(peer.sin_addr);
- string message = buffer;
-
- cout << clientip << " [" << clientport << "]# " << message << endl;
- }
- }

-
- // 1. 创建socket
- _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (_sockfd == -1)
- {
- cerr << "socket error: " << errno << " : " << strerror(errno) << endl;
- exit(2);
- }
- cout << "socket success: " << _sockfd << endl;
-
- struct sockaddr_in server;
- memset(&server, 0, sizeof(server));
- server.sin_family = AF_INET;
- server.sin_addr.s_addr = inet_addr(_serverip.c_str());
- server.sin_port = htons(_serverport);
-
- string message;
- while (!_quit)
- {
- cout << "Please Enter# ";
- cin >> message;
-
- sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server));
- }
- cc=g++
-
- .PHONY:all
- all:udpClient udpServer
-
- udpClient:udpClient.cc
- $(cc) -o $@ $^ -lpthread -std=c++11
- udpServer:udpServer.cc
- $(cc) -o $@ $^ -std=c++11
-
- .PHONY:clean
- clean:
- rm -f udpClient udpServer
- #pragma once
-
- #include <iostream>
- #include <string>
- #include <cerrno>
- #include <cstring>
- #include <cstdlib>
- #include <strings.h>
-
- #include <netinet/in.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
-
- namespace Client
- {
- using namespace std;
-
- class udpClient
- {
- public:
- udpClient(const string &serverip, const uint16_t &serverport)
- : _serverip(serverip), _serverport(serverport), _quit(false), _sockfd(-1)
- {
- }
- void initClient()
- {
- // 1. 创建socket
- _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (_sockfd == -1)
- {
- cerr << "socket error: " << errno << " : " << strerror(errno) << endl;
- exit(2);
- }
- cout << "socket success: " << _sockfd << endl;
-
- // 2. client要不要bind[不需要的] , client要不要显示的bind,需不需要程序员自己bind? 不需要
- // 写服务器的一家公司,写客户端是无数家公司 -- 因此让OS自动形成端口进行bind! -- OS在什么时候,如何bind
- }
- void run()
- {
- struct sockaddr_in server;
- memset(&server, 0, sizeof(server));
- server.sin_family = AF_INET;
- server.sin_addr.s_addr = inet_addr(_serverip.c_str());
- server.sin_port = htons(_serverport);
-
- string message;
- while (!_quit)
- {
- cout << "Please Enter# ";
- cin >> message;
-
- sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server));
- }
- }
- ~udpClient()
- {
- }
-
- private:
- int _sockfd;
- string _serverip;
- uint16_t _serverport;
- bool _quit;
- };
- } // namespace Client
-

- #include "udpClient.hpp"
- #include <memory>
-
- using namespace Client;
-
- static void Usage(string proc)
- {
- cout << "\nUsage:\n\t" << proc << " local_ip local_port\n\n";
- }
-
- // ./udpClient server_ip server_port
- int main(int argc, char *argv[])
- {
- if (argc != 3)
- {
- Usage(argv[0]);
- exit(1);
- }
-
- string serverip = argv[1];
- uint16_t serverport = atoi(argv[2]); // 字符串转整数
-
- unique_ptr<udpClient> ucli(new udpClient(serverip, serverport));
-
- ucli->initClient();
- ucli->run();
-
- return 0;
- }
-

- #include <iostream>
- #include <string>
- #include <cerrno>
- #include <cstring>
- #include <cstdlib>
- #include <strings.h>
- #include <functional>
-
- #include <netinet/in.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
-
- using namespace std;
-
- namespace Server
- {
- enum
- {
- SOCKET_ERR = 1,
- BIND_ERR,
- OPEN_ERR
- };
-
- const int NUM = 1024;
- static const string defaultIp = "0.0.0.0";
-
- class udpServer
- {
-
- public:
- udpServer(const uint16_t &port, const string ip = defaultIp)
- : _serverport(port), _serverip(defaultIp), _sockfd(-1)
- {
- // cout << "拷贝构造" << endl;
- }
-
- void initServer()
- {
- // 1. 套接字的创建
- _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (_sockfd == -1)
- {
- cerr << "socket error :" << errno << " : " << strerror(errno) << endl;
- exit(SOCKET_ERR);
- }
- cout << "socket success : " << _sockfd << endl;
-
- // 2. bind
- struct sockaddr_in local;
- bzero(&local, sizeof(local)); // 初始化local
-
- local.sin_family = AF_INET;
-
- // 1. 主机转网络 点分十进制转int
- local.sin_addr.s_addr = inet_addr(_serverip.c_str());
- // local.sin_addr.s_addr = INADDR_ANY;
- local.sin_port = htons(_serverport);
- int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
-
- if (n == -1)
- {
- cerr << "bind error: " << errno << " : " << strerror(errno) << endl;
- exit(BIND_ERR);
- }
- }
- void start()
- {
- char buffer[NUM];
- for (;;)
- {
- struct sockaddr_in peer;
- socklen_t len = sizeof(peer);
- //
- ssize_t s = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
-
- if (s > 0)
- {
- // 读取数据
- buffer[s] = 0;
- uint16_t clientport = ntohs(peer.sin_port);
- string clientip = inet_ntoa(peer.sin_addr);
- string message = buffer;
-
- cout << clientip << " [" << clientport << "]# " << message << endl;
- }
- }
- }
-
- ~udpServer()
- {
- }
-
- private:
- int _sockfd;
- uint16_t _serverport;
- string _serverip;
- };
- } // udpServer
-

- #include "udpServer.hpp"
- #include <memory>
-
- using namespace Server;
- using namespace std;
-
- static void Usage(string proc)
- {
- cout << "\nUsage:\n\t" << proc << " local_port\n\n";
- }
-
- // ./udpClient server_ip server_port
- int main(int argc, char *argv[])
- {
- if (argc != 2)
- {
- Usage(argv[0]);
- exit(1);
- }
-
- uint16_t port = atoi(argv[1]); // 字符串转整数
-
- unique_ptr<udpServer> usvr(new udpServer(port));
-
- usvr->initServer();
-
- usvr->start();
-
- return 0;
- }
-
-
-
-
-
-
-
-

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。