基于Linux的C++之网络编程

套接字的基本概念

通信类型: 控制套接字如何传输和处理数据,数据以包的形式传输

  • 连接(connection)类型:确保所有包依序传输,如果丢包,则请求重传
  • 数据报(datagram)类型:不保证包的到达顺序,包可能丢失

名空间: 指定套接字地址格式

  • 本地名空间:套接字地址为普通文件名
  • Internet名空间:套接字地址由Internet地址和端口号(用于区分一台主机上的多个套接字)确定

协议: 确定数据如何传输

套接字函数

socket()函数: 创建套接字

  • 原型:int socket(int domain,int type,int protocol);
  • 参数:名空间、通信类型和协议
  • 名空间:PF_LOCAL(本地)或PF_INET(Internet)
  • 通信类型:SOCK_STREAM(连接类型)或SOCK_DGRAM(数据报类型)
  • 协议:传递0,让系统自动选择协议(通常为最佳协议)
  • 返回值:套接字描述符

close()函数: 释放套接字

  • 原型:int close(int fd);

connect()函数: 创建两个套接字之间的连接

  • 客户发起此系统调用,试图与服务器建立套接字连接
  • 原型:int connect(int sockfd,const struct sockaddr* addr,socklen_t addrlen);
  • 参数:sockfd 为文件描述符; addr 为指向套接字地址结构体指针(服务器地址);addrlen 为服务器地址字符串的长度
  • 返回值:0 连接成功; -1 连接失败

send()函数: 发送数据

  • 原型: ssize_t send(int sockfd,const void* buf,size_t len,int flags);
  • 只有在套接字处于连接状态时才可调用

bind()函数: 绑定套接字与其服务器地址

  • 原型:int bind(int sockfd,const struct sockaddr* addr,socklen_t addrlen);

listen()函数: 侦听客户连接

  • 原型:int listen(int sockfd,int backlog);
  • 参数:backlog 指定有多少个连接可以进入队列,超出该值的连接将被抛弃

accept()函数: 接受连接,为该连接创建一个新的套接字

  • 原型 int accept(int sockfd,struct sockaddr* addr,socklen_t addrlen);
  • 参数: addr 为指向套接字地址结构体(客户地址)的指针
  • 返回值:创建一个新的套接字,以接受客户连接,返回值为新的套接字文件描述符
  • 原先套接字文件描述符可以继续接受新连接

本地套接字示例:服务器端

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

//持续读取消息,直到套接字关闭或接收到客户发送的“quit”消息
// 前者返回true,后者返回 false,服务器随后将停止服务

bool Serve(int client_socket)
{
  while (true) {
    int length;
    char* msg;
    //从套接字中读取文本消息的长度,返回值为0表示客户连接已关闭
    if(read(client_socket,&length,sizeof(length)) == 0)
      return true;
    msg = new char[length];
    read(client_socket,msg,length);
    std::cout<<msg<<std::endl;
    if(!strcmp(msg,"quit"))  {delete[] msg,msg = NULL;return false;}
    else delete[] msg, msg = NULL;
  }
}

int main(int argc,char* const argv[])
{
  const char* const socket_name = argv[1];
  ing socket_fd;
  struct sockaddr_un name;
  bool serving = true;
  //创建套接字
  socket_fd = socket(PF_LOCAL,SOCK_STREAM,0);
  //设定服务器性质
  name.sun_family = AF_LOCAL;
  strcpy(name.sun_path,socket_name);
  // 绑定套接字
  bind(socket_fd,(struct sockaddr*)&name,SUN_LEN(&name));
  //侦听客户连接
  listen(socket_fd,5);
  //重复接受连接,直到某个客户发出“quit”消息
  while(serving)
  {
    struct sockaddr_un client_name;
    socklen_t client_name_len;
    int client_socket_fd;
    //接受客户连接请求
    client_socket_fd = accept(socket_fd,(struct sockaddr*)&client_name,&client_name_len);
    serving = Serve(client_socket_fd); //服务连接请求
    close(socket_fd);//关闭客户连接
  }
  close(socket_fd);
  unlink(socket_name); //删除套接字文件
  return 0;
}

本地套接字示例,客户端

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

void SendMsg(int socket_fd,const char* msg)
{
  int length = strlen(msg) + 1;
  write(socket_fd,&length,sizeof(length));
  write(socket_fd,msg,length);
}
int main(int argc, char const *argv[]) {
  const char* const socket_name = argv[1];
  const char* const msg = argv[2];
  int socket_fd;
  struct sockaddr_un name;
  //创建套接字
  socket_fd = socket(PF_LOCAL,SOCK_STREAM,0);
  //套接字地址中存储服务器名称
  name.sun_family = AF_LOCAL;
  strcpy(name.sun_path,socket_name);
  //连接
  connect(socket_fd,(struct sockaddr*)&name,SUN_LEN(&name));
  //发送消息
  SendMsg(socket_fd,msg);
  close(socket_fd);
  return 0;
}

本地套接字示例:运行

程序测试运行

  • 编译链接服务端程序和客户端程序
  • 进入服务端程序目录,在终端输入:./server/tmp/socket; ./server 为服务器端程序名, /tmp/socket 为本服务器启动后的套接字文件名
  • 进入客户端程序目录,在终端中输入:./client/tmp/socket"Hello World!"; ./client 为客户端程序名
  • 停止服务器,在客户端输入命令:./client/tmp/socket"quit"

网络套接字示例:客户端

#include <iostream>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

// 请求Web服务器的主页
void GetHomepage(int socket_fd)
{
  char buffer[8192];
  sprintf(buffer,"GET /
");
  write(socket_fd,buffer,strlen(buffer));
  while(true){
    ssize_t count = read(socket_fd,buffer,8192);
    if(count == 0) return;
    fwrite(buffer,sizeof(char),count,stdout);
  }
}

int main(int argc, char const *argv[])
{
  int socket_fd;
  struct sockaddr_in name;
  struct hostent* hostinfo;
  socket_fd = socket(PF_INET,SOCK_STREAM,0);
  name.sin_family = AF_INET;
  hostinfo =  gethostbname(argv[1]);
  if(hostinfo == NULL) return 1;
  else name.sin_addr = *((struct in_addr*)hostinfo ->h_addr);
  name.sin_port = htons(80);
  if(connect(socket_fd,(struct in_addr*)&name,sizeof(struct sockaddr_in)) == -1) {
  perror("Failure to connect the server.");
  return 2;
}
  GetHomepage(socket_fd);
  return 0;
}

“`

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一门linuxc++通讯架构实战课程,针对c/c++语言已经掌握的很熟并希望进一步深造以将来用c++linux下从事网络通讯领域/网络服务器的开发和架构工作。这门课程学习难度颇高但也有着极其优渥的薪水(最少30K月薪,最高可达60-80K月薪),这门课程,会先从nginx源码的分析和讲解开始,逐步开始书写属于自己的高性能服务器框架代码,完善个人代码库,这些,将会是您日后能取得高薪的重要筹码。本课程原计划带着大家逐行写代码,但因为代码实在过于复杂和精细,带着写代码可能会造成每节课至少要4~5小时的超长时间,所以老师会在课前先写好代码,主要的时间花费在逐行讲解这些代码上,这一点望同学们周知。如果你觉得非要老师领着写代码才行的话,老师会觉得你当前可能学习本门课程会比较吃力,请不要购买本课程,以免听不懂课程并给老师差评,差评也会非常影响老师课程的销售并造成其他同学的误解。 这门课程要求您具备下面的技能:(1)对c/c++语言掌握的非常熟练,语言本身已经不是继续学习的障碍,并不要求您一定熟悉网络或者linux;(2)对网络通讯架构领域有兴趣、勇于挑战这个高难度的开发领域并期望用大量的付出换取高薪;在这门课程中,实现了一个完整的项目,其中包括通讯框架和业务逻辑框架,浓缩总结起来包括如下几点:(1)项目本身是一个极完整的多线程高并发的服务器程序;(2)按照包头包体格式正确的接收客户端发送过来的数据包, 完美解决收包时的数据粘包问题;(3)根据收到的包的不同来执行不同的业务处理逻辑;(4)把业务处理产生的结果数据包正确返回给客户端;本项目用到的主要开发技术和特色包括:(1)epoll高并发通讯技术,用到的触发模式是epoll中的水平触发模式【LT】;(2)自己写了一套线程池来处理业务逻辑,调用适当的业务逻辑处理函数处理业务并返回给客户端处理结果;(3)线程之间的同步技术包括互斥量,信号量等等;(4)连接池中连接的延迟回收技术,这是整个项目中的精华技术,极大程度上消除诸多导致服务器程序工作不稳定的因素;(5)专门处理数据发送的一整套数据发送逻辑以及对应的发送线程;(6)其他次要技术,包括信号、日志打印、fork()子进程、守护进程等等;
Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇章。 Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念(对等通信、封装、分用、端口) 02TCPIP基础(二) 最大传输单元(MTU)/路径MTU 以太网帧格式 ICMP ARP RARP 03TCPIP基础(三) IP数据报格式 网际校验和 路由 04TCPIP基础(四) TCP特点 TCP报文格式 连接建立三次握手 连接终止四次握手 TCP如何保证可靠性 05TCPIP基础(五) 滑动窗口协议 UDP特点 UDP报文格式 Linux网络编程之socket编程篇 06socket编程(一) 什么是socket IPv4套接口地址结构 网络字节序 字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户 /服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-per-conection) 点对点聊天程序实现 09socket编程(四) 流协议与粘包 粘包产生的原因 粘包处理方案 readn writen 回射客户/服务器 10socket编程(五) read、write与recv、send readline实现 用readline实现回射客户/服务器 getsockname、getpeername gethostname、gethostbyname、gethostbyaddr 11socket编程(六) TCP回射客户/服务器 TCP是个流协议 僵进程与SIGCHLD信号 12socket编程(七) TCP 11种状态 连接建立三次握手、连接终止四次握手 TIME_WAIT与SO_REUSEADDR SIGPIPE 13socket编程(八) 五种I/O模型 select 用select改进回射客户端程序 14socket编程(九) select 读、写、异常事件发生条件 用select改进回射服务器程序。 15socket编程(十) 用select改进第八章点对点聊天程序 16socket编程(十一) 套接字I/O超时设置方法 用select实现超时 read_timeout函数封装 write_timeout函数封装 accept_timeout函数封装 connect_timeout函数封装 17socket编程(十二) select限制 poll 18socket编程(十三) epoll使用 epoll与select、poll区别 epoll LT/ET模式 19socket编程(十四) UDP特点 UDP客户/服务基本模型 UDP回射客户/服务器 UDP注意点 20socket编程(十五) udp聊天室实现 21socket编程(十六) UNIX域协议特点 UNIX域地址结构 UNIX域字节流回射客户/服务 UNIX域套接字编程注意点 22socket编程(十七) socketpair sendmsg/recvmsg UNIX域套接字传递描述符字 Linux网络编程之进程间通信篇 23进程间通信介绍(一) 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) 消息队列 IPC对象数据结构 消息队列结构 消息队列在内核中的表示 消息队列函数 26System V消息队列(二) msgsnd函数 msgrcv函数 27System V消息队列(三) 消息队列实现回射客户/服务器 28共享内存介绍 共享内存 共享内存示意图 管道、消息队列与共享内存传递数据对比 mmap函数 munmap函数 msync函数 29System V共享内存 共享内存数据结构 共享内存函数 共享内存示例 30System V信号量(一) 信

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值