Linux-----网络套接字编程
创始人
2024-01-30 23:40:59
0

文章目录

    • 铺垫一下概念知识
    • 基于UDP协议下的套接字编程
    • 基于TCP协议下的套接字编程

铺垫一下概念知识

我们知道IP地址是用来标识主机唯一性的。
而源IP地址表示从哪个主机来, 目的IP地址表示去哪个主机。

端口号(port):
1,标识进程唯一性的。也就是说,一个端口号用来标识一个进程。
2,端口号是一个2字节16位的整数。

同样的:多个端口号可以对应一个进程, 多个进程不能对应一个端口。
因为必须通过端口号找到唯一一个进程。
IP地址 + 端口号(port) 就可以表示互联中的一台主机中的一个进程。

源端口号和目的端口号:传输层的数据段中有两个端口号,分别叫做目的端口号和源端口号,表示数据是发给哪个进程,
由哪个进程发的

我们知道,网络通信的本质就是进程间通信。
在这里插入图片描述

TCP协议:
1,传输层协议
2,有链接
3,可靠
4,面向字节流(数据从一方流向另一方)。

UDP协议
1,传输层协议
2,无连接
3,不可靠
4,面向数据报。

这里的可靠和不可靠是中性词,可靠肯定是要更多资源去维护的。如银行取钱那肯定是要可靠的。
其他的不一定要可靠。

网络字节序的概念:
其实在内存中分大小端。
小端:数据的低位存放在低地址
大端:数据的低位存放在高地址

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。
发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出
如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可。

网络字节序和主机字节序的相关转换函数:
#include
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

h----host主机, n-----network网络。

基于UDP协议下的套接字编程

UDP协议下的相关函数操作
在这里插入图片描述

服务端:

#include 
#include 
#include 
#include #include   //这两个头文件是 struct sockaddr_in
#include using namespace std;void Usage(const char* proc)
{cout << "Usage:" << endl << "./server  " << "server.port";
}//   ./server server.port
int main(int argc, char* argv[])
{if(argc != 2){Usage(argv[0]);return 1;}//1 创建套接字(网络文件), sock---文件描述符int sock = socket(AF_INET, SOCK_DGRAM, 0);if(sock < 0){cout << "sock fail" << endl;return 2;}//2  bind   绑定ip地址和端口号portstruct sockaddr_in local;local.sin_family = AF_INET;local.sin_port = htons(atoi(argv[1]));local.sin_addr.s_addr = INADDR_ANY;  //服务端可以任意绑定if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0){cout << "bind fail" << endl;return 3;}//提供服务char buff[1024];while(1){struct sockaddr_in peer;memset(&peer, 0 , sizeof(peer));socklen_t len = sizeof(peer);//peer 返回的客户端的ip + 端口号的属性集合 sockaddrssize_t s = recvfrom(sock, buff, sizeof(buff) , 0, (struct sockaddr*)&peer, &len);if(s > 0){//成功接受buff[s] = 0;cout << "clinet #" << buff << endl;const char* ch = "我是服务器, 你好啊";sendto(sock, ch, strlen(ch), 0, (struct sockaddr*)&peer, len);}else{cout << "recvfrom fail" << endl;return 3;}}return 0;
}

客户端:

#include 
#include 
#include 
#include #include   //这两个头文件是 struct sockaddr_in
#include 
using namespace std;void Usage(const char* proc)
{cout << "Usage" << endl << proc << "server.ip  server.port" << endl; 
}// ./client   server.ip   server.port
int main(int argc, char* argv[])
{if(argc != 3){Usage(argv[0]);return 1;}//1 创建套接字int sock = socket(AF_INET, SOCK_DGRAM, 0);if(sock < 0){cout << "sock fail" << endl;return 1;}//不需要绑定,OS会自动绑定struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(atoi(argv[2]));      //端口号server.sin_addr.s_addr = inet_addr(argv[1]); //ipwhile(1){cout << "client:" ;char line[1024];cin >> line;sendto(sock, line, sizeof(line), 0, (struct sockaddr*)&server, sizeof(server));//ret 占位用,无其他作用struct sockaddr_in ret;socklen_t len = sizeof(ret);char buff[1024];ssize_t s = recvfrom(sock, buff, sizeof(buff), 0, (struct sockaddr*)&ret, &len);if(s < 0){cout << "client recvfron fail" << endl;return 4;}cout << "server say" << buff << endl << endl;;}return 0;
}

基于TCP协议下的套接字编程

相关操作函数的总结:
1,创建socket的过程,socket()本质是创建网络文件,与系统相关
2,bind() sockaddr_in ----> 填入ip + port 本质是将ip + port 与网络文件相关联
3, listen() 设置该socket文件的状态,允许客户端来链接我
4 ,accept() 获取新连接到应用层,以文件描述符为代表,OS中肯定会存在大量的链接,如何管理呢?—>先描述,再组织
5, read/write 本质就是进行网络通信,而对于用户来说,就是在进行文件的正常读写。
6, close() ,关闭文件, 系统层面上,释放曾经申请的文件资源和链接资源
7, connect() 本质是发起链接, 在系统层面上,构建一个报文发过去。

客户端:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;void Usage(const char* proc)
{cout << "Usage:" << endl << proc << "   port" << endl;   
}void ServerIO(int new_sock)
{//开始服务while(1){char buff[1024];memset(buff, 0, sizeof(buff));ssize_t s = read(new_sock, buff, sizeof(buff));if(s > 0){cout << "client say#" << buff << endl;const char* ch = "server recv";write(new_sock, ch, strlen(ch));}else if(s == 0){//对端关闭}else{cout << "new_sock fail " << endl;return ;}}}void* handler(void* args)
{int* p = (int*)args;pthread_detach(pthread_self());ServerIO(*p);close(*p);
}int main(int argc, char* argv[])
{if(argc != 2){Usage(argv[0]);return 1;}//1, 创建套接字(网络文件) , AF_INFT是ipv4, sock_stream 是面向字节流int sock = socket(AF_INET, SOCK_STREAM, 0);if(sock < 0){cout << "sock fail" << endl;return 2;}//2 bindstruct sockaddr_in local;local.sin_family = AF_INET;local.sin_port = htons(atoi(argv[1]));local.sin_addr.s_addr = INADDR_ANY;if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0){cout << "bind error" << endl;return 3;}//3  监听if(listen(sock,5) < 0){cout << "listen fail" << endl;return 4;}//4 提供服务while(1){struct sockaddr_in peer;socklen_t len = sizeof(peer);//new sock 是提供服务的套接字, sock是用于监听的套接字//          提供服务               在线拉客int new_sock = accept(sock, (struct sockaddr*)&peer, &len);if(new_sock < 0){continue;}//通过创建进程来实现可对多个客户同时来进行服务/*signal(SIGCHLD, SIG_IGN);pid_t id = fork();if(id == 0){//子进程关闭与自己无关的文件描述符close(sock);ServerIO(new_sock);close(new_sock);}else if(id < 0){return 7;}else{//panrent}*///通过创建线程的方式来实现对多个客户同时进行服务pthread_t tid;int* pram = new int(new_sock);pthread_create(&tid, nullptr, handler, pram);}return 0;
}

用户端:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;void Usage(const char* proc)
{cout << "Usage:" << endl << proc << "   port" << endl;   
}int main(int argc, char* argv[])
{if(argc != 2){Usage(argv[0]);return 1;}//1, 创建套接字(网络文件) , AF_INFT是ipv4, sock_stream 是面向字节流int sock = socket(AF_INET, SOCK_STREAM, 0);if(sock < 0){cout << "sock fail" << endl;return 2;}//2 bindstruct sockaddr_in local;local.sin_family = AF_INET;local.sin_port = htons(atoi(argv[1]));local.sin_addr.s_addr = INADDR_ANY;if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0){cout << "bind error" << endl;return 3;}//3  监听if(listen(sock,5) < 0){cout << "listen fail" << endl;return 4;}//4 提供服务while(1){struct sockaddr_in peer;socklen_t len = sizeof(peer);//new sock 是提供服务的套接字, sock是用于监听的套接字//          提供服务               在线拉客int new_sock = accept(sock, (struct sockaddr*)&peer, &len);if(new_sock < 0){continue;}//开始服务while(1){char buff[1024];memset(buff, 0, sizeof(buff));ssize_t s = read(new_sock, buff, sizeof(buff));if(s > 0){cout << "client say#" << buff << endl;const char* ch = "server recv";write(new_sock, ch, strlen(ch));}else if(s == 0){//对端关闭}else{cout << "new_sock fail " << endl;return 6;}}}return 0;
}

相关内容

热门资讯

普京形象出现在动画片中   参考消息援引俄新社12月17日报道,俄罗斯动画影片制片厂新闻办公室证实,普京总统的形象将出现在尚...
走进这里,仿佛拥有整个世界   “看前头,嘎隆拉隧道到了!”唐师傅在驾驶座上高喊,我听后心里一颤:嘎隆拉,十多年来,这个让我心心...
被赖清德“约谈”后,台湾海基会...   台湾海基会现任董事长吴丰山18日突然宣布辞职,他也是继前任郑文灿之后,又一位在任内请辞的台湾海基...
“量子科技第一股”董事长突然去... 12月18日晚间,《每日经济新闻》记者从多个渠道获悉,国盾量子董事长吕品已于当日离世。 安徽合肥高新...
视频丨破冰突围、深耕自研 我国...   党的二十届四中全会提出,要“构建以先进制造业为骨干的现代化产业体系”。“十四五”期间,随着“3亿...
科技加持“美丽经济” 各地年宵...   央视网消息:元旦临近,各地花卉市场迎来销售高峰。在山东菏泽市,蝴蝶兰和杜鹃等年宵花卉集中上市,商...
漫评:“递火”   漫画作者:马宏亮(人民网版权图片,未经授权请勿转载。)  日本首相高市早苗此前发表涉台严重错误言...
泽连斯基就安全保障问题强调乌方...   总台记者获悉,当地时间18日,乌克兰总统泽连斯就乌美安全保障合作、和平谈判推进及与美国政要沟通等...