2024年C C++最新Linux-socket编程以及TCP、UDP实例_c udp msghdr实例(5),2024年最新如何成为杰出的程序员

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!


接受连接



accet(int socketfd,struct sockaddr * my_addr, int addrlen)

从队列中接受一个连接


发起连接



connect(int socketfd,struct sockaddr * my_addr, int addrlen)


关闭连接



close(int fd)


tcp数据读写



recv(int fd,void*buf,size_t len,int flags)
send(int fd,const void *buf,size_t len,int flags)
flag 有一些特别的参数
持续监听对方的回应
不经过路由表
对socket非阻塞
发送紧急数据
不接受sig信号等等


udp数据读写



recvfrom(int fd,void*buf,size_t len,int flags,struct sockaddr * my_addr, int addrlen)

sendto(int fd,const void*buf,size_t len,int flags,struct sockaddr * my_addr, int addrlen)


通用数据读写



recvmsg(int fd,struct msghdrmsg,int flags);
sendmsg(int fd,struct msghdr
msg,int flags);



struct msghdr
{
void* msg_name;
socklen_t msg_namelen;
struct iovecmsg_iov;
int msg_iovlen;
void
msg_control;
socklen_t msg_controllen;
int msg_flags;
};

struct iovec
{
void *iov_base;
size_t iov_len;
};


带外标记判断



int sockatmark(int sockfd);


地址信息函数



int getsockname(int socketfd,struct sockaddr * my_addr, int addrlen);//本端的地址信息
int getpeername(int socketfd,struct sockaddr * my_addr, int addrlen);//远端的地址信息


socket选项



获取socket选项
getsockopt(int socketfd,int opt_name,voidoption_value,socket_t restrict option_len)
设置socket选项
getsockopt(int socketfd,int opt_name,void
option_value,socket_t restrict option_len)

这个可以查看手册。



选项名称        说明                  数据类型

SOL_SOCKET

SO_BROADCAST      允许发送广播数据            int
SO_DEBUG        允许调试                int
SO_DONTROUTE      不查找路由               int
SO_ERROR        获得套接字错误             int
SO_KEEPALIVE      保持连接                int
SO_LINGER        延迟关闭连接              struct linger
SO_OOBINLINE      带外数据放入正常数据流         int
SO_RCVBUF        接收缓冲区大小             int
SO_SNDBUF        发送缓冲区大小             int
SO_RCVLOWAT       接收缓冲区下限             int
SO_SNDLOWAT       发送缓冲区下限             int
SO_RCVTIMEO       接收超时                struct timeval
SO_SNDTIMEO       发送超时                struct timeval
SO_REUSERADDR      允许重用本地地址和端口         int
SO_TYPE         获得套接字类型             int
SO_BSDCOMPAT      与BSD系统兼容              int

IPPROTO_IP

IP_HDRINCL       在数据包中包含IP首部          int
IP_OPTINOS       IP首部选项               int
IP_TOS         服务类型
IP_TTL         生存时间                int

IPPRO_TCP

TCP_MAXSEG       TCP最大数据段的大小           int
TCP_NODELAY       不使用Nagle算法             int


获取主机信息



根据名字获取主机信息
struct hostent* gethostbyname(const char name)
根据ip获取主机信息
struct hostent
gethostbyaddr(const void *addr,size_t len,int type)



struct hostent
{
char h_name;//主机名
char
* h_aliases;//主机别名,可能有多个
int h_addrtype;//地址类型
int h_length;// 地址长度
char ** h_addr_list//按照网络字节序列列出idp地址列表
}


获取服务信息



//根据 名字,端口号获取服务信息
struct servent*getservbyname(const char *name,const char proto);
//根据服务类型,端口号获取服务信息
struct servent
getservbyport(int port,const char *proto);



struct servent{
    char *h_name;//主机名
    char** h_aliases;//主机别名,可能有多个
    int  s_port;//端口号
    char *s_proto;//服务类型,tcp或者upd等

}

通过主机名获取ip地址



int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );


通过socket地址获取主机名



int getnameinfo (const struct sockaddr *sockaddr, socklen_t addrlen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags) ;


tcp编程的例子server



//
// main.cpp
// linux_socket_api
//
// Created by bikang on 16/11/2.
// Copyright © 2016年 bikang. All rights reserved.
//

#include

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>

//using namespace std;

#define BUFFER_SIZE 1024

void tsocket(int argc, const char * argv[]);

int main(int argc, const char * argv[]) {
tsocket(argc,argv);
return 0;
}
void tsocket(int argc, const char * argv[]){
if(argc < 3){
exit(-1);
}

const char* ip = argv[1];
int port = atoi(argv[2]);
int backlog = atoi(argv[3]);

std::cout << "ip=" << ip << " port="<<port << " backlog=" << backlog  << std::endl;

int fd;
int check_ret;

fd = socket(PF_INET,SOCK_STREAM , 0);
assert(fd >= 0);

struct sockaddr_in address;
bzero(&address,sizeof(address));

//转换成网络地址
address.sin_port = htons(port);
address.sin_family = AF_INET;
//地址转换
inet_pton(AF_INET, ip, &address.sin_addr);
//设置socket buffer大小
int recvbuf = 4096;
int len = sizeof( recvbuf );
setsockopt( fd, SOL_SOCKET, SO_RCVBUF, &recvbuf, sizeof( recvbuf ) );
getsockopt( fd, SOL_SOCKET, SO_RCVBUF, &recvbuf, ( socklen_t* )&len );
printf( "the receive buffer size after settting is %d\n", recvbuf );



//绑定ip和端口
check_ret = bind(fd,(struct sockaddr*)&address,sizeof(address));
assert(check_ret >= 0);

//创建监听队列,用来存放待处理的客户连接
check_ret = listen(fd, backlog);
assert(check_ret >= 0);

struct sockaddr_in addressClient;
socklen_t clientLen = sizeof(addressClient);
//接受连接,阻塞函数
int connfd = accept(fd, (struct sockaddr*)&addressClient, &clientLen);
if(connfd < 0){
    std::cout << "accept error";
}else{
    //打印客户端信息
    char showData[INET_ADDRSTRLEN];
    std::cout <<inet_ntop(AF_INET,&addressClient.sin_addr,showData,INET_ADDRSTRLEN)<<":" <<ntohs(addressClient.sin_port)<<std::endl;

    //接受数据
    const int BUF_LEN = 1024;
    char sockBuf[BUF_LEN];
    size_t ret;

    memset(sockBuf, '\0', BUF_LEN);
    ret = recv(connfd, sockBuf, BUF_LEN-1, 0);
    printf("ret=%ld,msg=%s\n",ret,sockBuf);

    memset(sockBuf, '\0', BUF_LEN);
    ret = recv(connfd, sockBuf, BUF_LEN-1, MSG_OOB);
    printf("ret=%ld,msg=%s\n",ret,sockBuf);

    memset(sockBuf, '\0', BUF_LEN);
    ret = recv(connfd, sockBuf, BUF_LEN-1, 0);
    printf("ret=%ld,msg=%s\n",ret,sockBuf);

    //获取本地socket信息
    struct sockaddr_in tmpAddress;
    clientLen = sizeof(tmpAddress);
    getsockname(fd, (struct sockaddr*)&tmpAddress, &clientLen);
    std::cout <<inet_ntop(AF_INET,&tmpAddress.sin_addr,showData,INET_ADDRSTRLEN)<<":" <<ntohs(tmpAddress.sin_port)<<std::endl;
    //获取远端socket信息
    getpeername(connfd,(struct sockaddr*)&tmpAddress, &clientLen );
    std::cout <<inet_ntop(AF_INET,&tmpAddress.sin_addr,showData,INET_ADDRSTRLEN)<<":" <<ntohs(tmpAddress.sin_port)<<std::endl;



    close(connfd);
}

close(fd);

}


tcp编程的例子client




//
// main.cpp
// linux_socket_api_client
//
// Created by bikang on 16/11/2.
// Copyright © 2016年 bikang. All rights reserved.
//
#include

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>

void tserver(int argc, const char * argv[]);

int main(int argc, const char * argv[]) {
tserver(argc,argv);
return 0;
}
void tserver(int argc, const char * argv[]){
std::cout << “t server” << std::endl;
if(argc < 3){
exit(-1);
}

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

cout << “t server” << std::endl;
if(argc < 3){
exit(-1);
}

[外链图片转存中…(img-DVwlGDoJ-1715551761306)]
[外链图片转存中…(img-QumuZQDR-1715551761306)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 Unix/Linux 系统下,我们可以使用 `sendmsg` 和 `recvmsg` 函数来传递文件句柄。下面是一个简单的示例代码: #### 发送进程代码 ```c #include <sys/types.h> #include <sys/socket.h> #include <sys/uio.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <errno.h> #define CONTROLLEN CMSG_LEN(sizeof(int)) int send_fd(int fd, int fd_to_send) { struct iovec iov[1]; struct msghdr msg; char buf[2]; // 发送任意数据 int ret; union { struct cmsghdr cm; char control[CONTROLLEN]; } control_un; struct cmsghdr *pcmsg; iov[0].iov_base = buf; iov[0].iov_len = 2; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; if (fd_to_send >= 0) { msg.msg_control = control_un.control; msg.msg_controllen = CONTROLLEN; pcmsg = CMSG_FIRSTHDR(&msg); pcmsg->cmsg_len = CONTROLLEN; pcmsg->cmsg_level = SOL_SOCKET; pcmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(pcmsg) = fd_to_send; } else { msg.msg_control = NULL; msg.msg_controllen = 0; buf[1] = 0; } buf[0] = 0; if ((ret = sendmsg(fd, &msg, 0)) < 0) { perror("sendmsg"); } return ret; } ``` #### 接收进程代码 ```c int recv_fd(int fd) { struct iovec iov[1]; struct msghdr msg; char buf[2]; int ret; union { struct cmsghdr cm; char control[CONTROLLEN]; } control_un; struct cmsghdr *pcmsg; iov[0].iov_base = buf; iov[0].iov_len = 2; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = control_un.control; msg.msg_controllen = CONTROLLEN; if ((ret = recvmsg(fd, &msg, 0)) < 0) { perror("recvmsg"); return -1; } if (buf[0] != 0) { printf("error: received %d bytes\n", ret); return -1; } if ((pcmsg = CMSG_FIRSTHDR(&msg)) != NULL && pcmsg->cmsg_len == CONTROLLEN) { if (pcmsg->cmsg_level != SOL_SOCKET) { printf("error: control level != SOL_SOCKET\n"); return -1; } if (pcmsg->cmsg_type != SCM_RIGHTS) { printf("error: control type != SCM_RIGHTS\n"); return -1; } return *(int *)CMSG_DATA(pcmsg); } else { return -1; } } ``` 使用示例: ```c #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> int main() { int fd[2]; int ret; char buf[256]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) { perror("socketpair"); exit(1); } int send_fd = open("file.txt", O_RDONLY); if (send_fd < 0) { perror("open"); exit(1); } if ((ret = fork()) < 0) { perror("fork"); exit(1); } if (ret == 0) { // 子进程 close(fd[0]); int recv_fd = recv_fd(fd[1]); if (recv_fd < 0) { exit(1); } printf("received fd: %d\n", recv_fd); read(recv_fd, buf, 256); printf("read: %s\n", buf); close(recv_fd); exit(0); } else { // 父进程 close(fd[1]); send_fd(fd[0], send_fd); close(send_fd); waitpid(ret, NULL, 0); exit(0); } } ``` 在这个示例中,父进程打开了 `file.txt` 文件,并将其文件描述符通过 `send_fd` 函数发送给了子进程。子进程通过 `recv_fd` 函数接收到了文件描述符,并读取了文件中的内容。注意,这个示例中并没有考虑错误处理,实际应用中需要根据实际情况进行完善。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值