报式套接字通讯实例
使用套接字通讯流程
被动端(先运行)
1、取得SOCKET
2、给SOCKET取得地址
3、收/发消息
4、关闭SOCKET
主动端
1、取得SOCKET
2、给SOCKET取得地址(可省略)
3、发/收消息
4、关闭SOCKET
各部分代码实现
proto.h代码如下:
#ifndef PROTO_H__
#define PROTO_H__//定义端口号
#define RCVPORT "1989"#define NAMESIZE 11//__attribute__((packed))表示结构体取消内存对齐
struct msg_st
{uint8_t name[NAMESIZE];uint32_t math;uint32_t chinese;
}__attribute__((packed));#endif
rcvder.c代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>#include "proto.h"#define IPSTRSIZE 40int main()
{int sd;//定义我端的地址laddrstruct sockaddr_in laddr,raddr;struct msg_st rbuf;socklen_t raddr_len;char ipstr[IPSTRSIZE];//使用AF_INET协议族中的默认协议(0),实现SOCK_DGRAMsd = socket(AF_INET,SOCK_DGRAM,0);if(sd < 0){perror("socket()");exit(0);}laddr.sin_family = AF_INET;//因为端口要在网络传输,所以使用htons转换,将本地(host)转为网络(net),宽度为shortladdr.sin_port = htons(atoi(RCVPORT));/*inet_pton将IP地址的点分式转为整数int inet_pton(int af,const char *src,void *dst)参数:af 协议族,要么是IPV4(AF_INET)要么是IPV6(AF_INET6)src 要转换的IP地址dst 转换后要放置的地址处*///"0.0.0.0"表示匹配的任意地址inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);//我端的地址和地址长度if(bind(sd,(void *)&laddr,sizeof(laddr)) < 0){perror("bind()");exit(1);}while(1){/*ssize_t recv(int sockfd,void *buf,size_t len,int flags)这个适用于流式套接字,一对一通讯ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,struct sockaddr *src_addr,socklen_t *addrlen)recvfrom是适用于报式套接字,非一对一的通讯,要记录传输数据地址从哪里来的*//*一定要初始化raddr_len的大小,否则回造成第一次打开地址不对,后面会对*/raddr_len = sizeof(raddr);recvfrom(sd,&rbuf,sizeof(rbuf),0,(void *)&raddr,&raddr_len);//使用inet_ntop();函数将ip大整数转为点分式inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE);printf("----MESSAGE FROM IP: %s port: %d---\n",ipstr,ntohs(raddr.sin_port));printf("NAME = %s\n",rbuf.name);printf("MATH = %d\n",ntohl(rbuf.math));printf("CHINESE = %d\n",ntohl(rbuf.chinese));}close(sd);exit(0);
}
编译执行结果如下:
使用netstat -anu命令查看udp网络状态,如果查看tcp使用netstat -ant命令,结果如下1989端口已经打开。
snder.c代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>#include "proto.h"int main(int argc,char *argv[])
{int sd;//将待发送的内容放到sbuf中struct msg_st sbuf;struct sockaddr_in raddr;if(argc < 2){fprintf(stderr,"Usage is short 2\n");exit(1);}sd = socket(AF_INET,SOCK_DGRAM,0);if(sd < 0){perror("socket()");exit(1);}//bind();/*ssize_t send(int sockfd,const void *buf,size_t len,int flags);这个是用于流式套接字,因为式一对一通讯ssize_t sendto(int sockfd,const void *buf,size_t len,int flags,const struct sockaddr *dest_addr,socklen_t addrlen);这个用于报式套接字,因为是一对多,所以要指定目的的地址和大小参数:sockfd socket函数的返回值buf 要发送的数据len 发送数据的长度,即下一个参数buf的大小flags 有无特殊要求,如无设置0选择默认dest_addr 目的地址addrlen 的地址的大小返回值成功 送出去的字符个数失败 -1*///填充sbuf要发送的数据strcpy(sbuf.name,"Alan");sbuf.math = htonl(rand()%100);sbuf.chinese = htonl(rand()%100);//设置远端的地址,分别设置协议族、端口、IP地址raddr.sin_family = AF_INET;raddr.sin_port = htons(atoi(RCVPORT));inet_pton(AF_INET,argv[1],&raddr.sin_addr);if(sendto(sd,&sbuf,sizeof(sbuf),0,(void *)&raddr,sizeof(raddr)) < 0){perror("sento()ssfd");exit(1);}puts("OK!");close(sd);exit(0);
}
编译运行结果如下:
使snder与rcver建立通信,先执行./rcver,再执行./snder,执行结果如下:
编译运行结果如下: