一,通信模型
服务器:
(1)创建socket,使用socket函数
(2)准备通信地址,使用结构体类型
(3)绑定socket和通信地址,使用bind函数
(4)监听,使用listen函数
(5)响应客户端的连接请求,使用accept函数
(6)进行通信,使用read/write函数
(7)关闭socket,使用close函数
客户端:
(1)创建socket,使用socket函数
(2)准备通信地址,使用服务器的地址
(3)连接socket和通信地址,使用connect函数
(4)进行通信,使用read/write函数
(5)关闭socket,使用close函数
二,UDP发送和接收函数
1,sendto函数
#include <sys/types.h>
#include <sys/socket.h>
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);
第一个参数:socket描述符,socket函数的返回值
第二个参数:被发送数据的首地址
第三个参数:被发送数据的大小
第四个参数:发送的标志,默认给0表示产生阻塞
第五个参数:数据接受方的通信地址
第六个参数:数据接受方通信地址的大小
返回值:成功返回实际发送的数据大小,失败返回-1
函数功能:主要用于将指定的消息发送到指定的地址上,
2,recvfrom函数
#include <sys/types.h>
#include <sys/socket.h>
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);
第一个参数:socket描述符,socket函数的返回值
第二个参数:存放接受到数据的缓冲区首地址
第三个参数:接受的数据大小
第四个参数:接受的标志,默认给0即可
第五个参数:保存数据发送方的通信地址(来电显示)
第六个参数:通信地址的大小
返回值:成功返回实际接受的数据大小,失败返回-1
函数功能:主要用于接受指定的数据并提供来电显示的功能
三,sockaddr_in(在netinet/in.h中定义):
struct sockaddr_in
{
short sin_family;/*Address family一般来说AF_INET(地址族)PF_INET(协议族)*/
unsigned short sin_port;/*Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/
struct in_addr sin_addr;/*IP address in network byte order(Internet address)*/
unsigned char sin_zero[8];/*Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐*/
};
sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储端口号,在linux下,端口号的范围0~65535,同时0~1024范围的端口号已经被系统使用或保留。
sin_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址
in_addr结构
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
五,UDP通讯代码
1,UDP服务器代码
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <netinet/in.h>
#include<arpa/inet.h>
int sockfd;
void sig_handler(int signo)
{
if (signo == SIGINT)
{
printf("server close\n");
close(sockfd);
exit(1);
}
}
void out_addr(struct sockaddr_in * clientaddr)
{
char ip[16];
int port;
memset(ip, 0, sizeof(ip));
inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr, ip, sizeof(ip));
port = ntohs(clientaddr->sin_port);
printf("client: %s(%d)\n", ip, port);
}
void do_service()
{
struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
//接收客户端的数据报文
if (recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&clientaddr, &len) < 0)
{
perror("recvfrom error");
}
else
{
out_addr(&clientaddr);
printf("client send into: %s \n", buffer);
//向客户端发送数据报文
long int t = time(0);
char *ptr = ctime(&t);
size_t size = strlen(ptr) * sizeof(char);
if (sendto(sockfd, ptr, size, 0, (struct sockaddr*)&clientaddr, len) < 0)
{
perror("sendto error");
}
}
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("usage: %s port \n", argv[0]);
exit(1);
}
if (signal(SIGINT, sig_handler) == SIG_ERR)
{
perror("signal sigint error");
exit(1);
}
/*1.创建socket*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket error");
exit(1);
}
int ret;
int opt = 1;
//设置套接字选项SO_REUSEADDR,1.保证停用的端口可以立即使用;2.在此程序不被终止的情况下,新启动的程序绑定相同的端口也会//成功,不过此程序端口会失效。
if ((ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0)
{
perror("setsockopt error");
exit(1);
}
/*2.调用bind函数对socket和地址进行绑定*/
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET; //IPv4
serveraddr.sin_port = htons(atoi(argv[1]));//port
serveraddr.sin_addr.s_addr = INADDR_ANY;//ip
if (bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
{
perror("bind error");
exit(1);
}
/*3.与客户端进行数据通信*/
while (1)
{
do_service();
}
return 0;
}
2,UDP客户端代码
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <memory.h>
int main(int argc, char* argv[])
{
if (argc < 3)
{
printf("usage: %s ip port\n", argv[0]);
exit(1);
}
/*1.创建socket*/
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("socket error");
exit(1);
}
/*2.调用recvfrom 、sendto等函数和服务器双向通信*/
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr);
//调用connect并不会像TCP编程中的三次握手,只是在内核在记录服务器端的一些地址信息(包括IP、端口等)
//这样后面即使不调用sendto指定服务器的地址,而只调用send也可以向服务器发送数据。
//建议调用connect,这样会保证客户端在接收的时候,只接收到来自指定服务器端的数据,而不会收到其它服务器的数据。
if (connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
{
perror("sendto error");;
exit(1);
}
char buffer[1024] = "hello linux";
//向服务器发送数据报文
if (sendto(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
{
perror("sendto error");
exit(1);
}
else
{
//接收服务器端发送的数据报文
memset(buffer, 0, sizeof(buffer));
if (recv(sockfd, buffer, sizeof(buffer), 0) < 0)
{
perror("recv error");
exit(0);
}
else
{
printf("%s", buffer);
}
}
return 0;
}
六,用于传输结构图数据的UDP代码
1,用于结构体数据传输的服务器代码
#include
#include
#include
#include
#include
#include
#define MAXLINE 1024
#define SERV_PORT 8888
struct MSG_PACK
{
char cmd;
char status;
short int len;
};
struct host
{
char UserName[20];
char Host[20];
char IP[20];
char PassWord [20];
char SubNet[512];
char Mode;
char ConState;
char Pin[20];
char ConTrol;
char RandPassword[10];
};
int main(void)
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0); /* create a socket */
/* init servaddr */
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
/* bind address and port to socket */
if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
perror("bind error");
exit(1);
}
do_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
close(sockfd);
return 0;
}
void do_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
for(;;)
{
len = clilen;
n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len); /* waiting for receive data */
printf ("n:%d , len=%d/n",n,len);
struct MSG_PACK pocket;
memcpy(&pocket,mesg,sizeof(struct MSG_PACK));
printf("~~~~~~~pocket1~~~~~~~%d/n",pocket.cmd);
printf("~~~~~~~pocket2~~~~~~~%d/n",pocket.status);
printf("~~~~~~~pocket3~~~~~~~%d/n",pocket.len);
struct host sHost2 ;
memcpy(&sHost2 , mesg + sizeof(struct MSG_PACK) , sizeof(struct host));
printf("-----sHost1-------%s/n",sHost2.UserName);
printf("-----sHost2-------%s/n",sHost2.Host);
printf("-----sHost3-------%s/n",sHost2.IP);
printf("-----sHost4-------%s/n",sHost2.PassWord);
printf("-----sHost5-------%s/n",sHost2.SubNet);
printf("-----sHost6-------%d/n",sHost2.Mode);
printf("-----sHost7-------%d/n",sHost2.ConState);
printf("-----sHost8-------%s/n",sHost2.Pin);
printf("-----sHost9-------%d/n",sHost2.ConTrol);
printf("-----sHost10-------%s/n",sHost2.RandPassword);
n = sendto(sockfd, mesg, n, 0, pcliaddr, len); /* 回发给client */
}
}
2,用于结构体数据传输的客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define minornode 0 //从节点向主节点发送连接请求
#define hostnode_return 1 //主节点响应从节点的请求
#define minornode_change 2 //从节点向主节点发送更新请求
#define hostnode_returnchange 3 //主节点响应更新请求
//包头的定义
struct MSG_PACK
{
char cmd;
char status;
short int len;
};
//定义host
struct host
{
char UserName[20];
char Host[20];
char IP[20];
char PassWord [20];
char SubNet[512];
char Mode;
char ConState;
char Pin[20];
char ConTrol;
char RandPassword[10];
};
int main()
{
char sentbuf[1024];
struct host newhost;
memset(&newhost,0,sizeof(struct host));
strcpy(newhost.UserName,"aaaa");
strcpy(newhost.Host,"www");
strcpy(newhost.IP,"192.168.8.103");
strcpy(newhost.PassWord,"1111");
strcpy(newhost.SubNet,"255.255.255.0");
newhost.Mode=0;
newhost.ConState=1;
strcpy(newhost.Pin,"20");
newhost.ConTrol=0;
strcpy(newhost.RandPassword,"122122");
//printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %s %s %s %s %s %d %d %s %d %s @@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",newhost.UserName,newhost.Host,newhost.IP,newhost.PassWord,newhost.SubNet,newhost.Mode,newhost.ConState,newhost.Pin,newhost.ConTrol,newhost.RandPassword);
struct MSG_PACK newpack;
newpack.cmd=1;
newpack.status=1;
newpack.len=sizeof(newhost);
//printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %d %d %d @@@@@@@@@@@@@@@@@@@@@@@@@@@ ",newpack.cmd,newpack.status,newpack.len);
memcpy(sentbuf,&newpack,sizeof(struct MSG_PACK));
memcpy(sentbuf+sizeof(struct MSG_PACK),&newhost,sizeof(struct host));
int iLen = sizeof(struct MSG_PACK)+ sizeof(struct host);
printf("-=-=-=-=-=-=-=-=-=-=-=-=%d ",iLen);
int sock;
//sendto中使用的对方地址
struct sockaddr_in servaddr;
//在recvfrom中使用的对方主机地址
struct sockaddr_in fromAddr;
unsigned int fromLen;
char recvBuffer[1024];
sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=inet_addr("192.168.8.200");
servaddr.sin_port = htons(8000);
if(sendto(sock,sentbuf,iLen,0,(struct sockaddr*)&servaddr,sizeof(servaddr)) != iLen)
{
perror("sendto error");
close(sock);
exit(1);
}
fromLen = sizeof(fromAddr);
if(recvfrom(sock,recvBuffer,1024,0,(struct sockaddr*)&fromAddr,&fromLen)<0)
{
perror("recvfrom error");
close(sock);
exit(1);
}
struct MSG_PACK pocket;
memcpy(&pocket , recvBuffer , sizeof(struct MSG_PACK));
printf("-----pocket1------->%d ",pocket.cmd);
printf("-----pocket2------->%d ",pocket.status);
printf("-----pocket3------->%d ",pocket.len);
struct host sHost2 ;
memcpy(&sHost2 , recvBuffer + sizeof(struct MSG_PACK) , sizeof(struct host));
printf("&&&&&&&&&&&&&&&&&&&& -----sHost1------->%s ",sHost2.UserName);
printf("-----sHost2------->%s ",sHost2.Host);
printf("-----sHost3------->%s ",sHost2.IP);
printf("-----sHost4------->%s ",sHost2.PassWord);
printf("-----sHost5------->%s ",sHost2.SubNet);
printf("-----sHost6------->%d ",sHost2.Mode);
printf("-----sHost7------->%d ",sHost2.ConState);
printf("-----sHost8------->%s ",sHost2.Pin);
printf("-----sHost9------->%d ",sHost2.ConTrol);
printf("-----sHost10------->%s &&&&&&&&&&&&&&&&&&&& ",sHost2.RandPassword);
close(sock);
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)