总得来说socket代码的开发是比较简单的一块,下面总结一下socket通信:
1. socket通信的基本流程:
a) 通过套接字和结构体进行声明和初始化
#include <sys/socket.h>
struct sockaddr_in serveraddr;
/*对结构体全部置零*/
bzero(&serveraddr,sizeof(serveraddr));
/*三个初始化即类别(ipv4、ipv6)、端口、地址*/
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(port);
serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
注意:1.这里对于server端地址赋值为INADDR_ANY。
另外对于客户端绑定端口号也赋值为INADDR_ANY。
/*创建套接字,我们使用UDP所以socket的第二个参数为SOCK_DGRAM*/
int client_descriptor = socket(AF_INET,SOCK_DGRAM,0);
/*绑定套接字和地址结构体*/
bind(client_descriptor,(struct sockaddr*)&clientaddr,sizeof(clientaddr));
- socket地址为广播地址
对于socket通信中若目的地址是广播地址的场景中,我们需要通过setsockopt()函数来进行修改配置才行。
int so_broadcast = 1;
setsockopt(client_descriptor,SOL_SOCKET,SO_BROADCAST,&so_broadcast,sizeof(so_broadcast));
重点说明完毕了,下面贴出udp的完整代码,这段代码应用背景是客户端向服务器端进行udp的查询(查询内容为一结构体),服务器给客户端提供响应。
客户端:(未固定端口号)
#include <stdlib.h>
#include <stddef.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include <time.h>
//请求&应答信令
//msg_type 1表示为请求,2表示为应答
//msg_status 0表示信道空闲,1表示为信道忙
typedef struct Msg {
int msg_type; //1 is request, 2 is answer
int msg_status;//0 is idle, 1 is busy
}MSG;
//note the arguments of send_msg
struct argu_send{
int sock;
struct sockaddr_in *adres;
};
void send_msg(struct argu_send *argr){
//新建一个套接字,用于向信道设备发送消息
//client_ip为信道设备的ip地址
int err_send;
time_t ticks;
struct sockaddr_in *serveradd;
serveradd = (struct sockaddr_in*)argr->adres;
struct Msg Msg_request;
char* SendBuf = (char*)malloc(sizeof(MSG));
Msg_request.msg_type = 1 ;
while(1){
memcpy(SendBuf,(char*)&Msg_request,(int)sizeof(Msg_request));
err_send=sendto(argr->sock,SendBuf,(int)sizeof(MSG),0,(struct sockaddr *)(serveradd),sizeof(*serveradd));
ticks=time(NULL);
printf("send%d\t%.24s\r\n",err_send,ctime(&ticks));
printf("message:\t%d\n",Msg_request.msg_type);
printf("------------------------------------\n");
sleep(3);
}
}
void get_msg(int *socket_descriptor){
int err_recv;
int sock = *socket_descriptor;
struct Msg * Msg_answer;
printf("sock= %d\n",sock);
char* RecvBuf = (char*)malloc(sizeof(MSG));
while(1){
err_recv=recvfrom(sock,RecvBuf,(int)sizeof(MSG),0,NULL,NULL);
if(err_recv != -1){
Msg_answer = (struct Msg *)RecvBuf;
printf("Recvive: Type= %d, Status= %d\n",Msg_answer->msg_type,Msg_answer->msg_status);
printf("****************************\n");
}
}
}
int main(int argc, char** argv){
/* check args */
if (argc !=2){
printf("Usage: udp_request IP\n");
exit(1);
}
//创建两个线程
pthread_t threadrecv,threadsend;
void *retval;
int port = 4600;
int server_descriptor;
struct sockaddr_in serveraddr;
/* init serveraddr */
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(port);
inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);
server_descriptor= socket(AF_INET,SOCK_DGRAM,0);//creat a socket
if(server_descriptor == -1){
printf("Create Socket Failed!\n");
exit(1);
}
struct argu_send args;
args.adres =&serveraddr;
args.sock = server_descriptor;
pthread_create(&threadsend,NULL,(void*)(&send_msg),&args);
pthread_create(&threadrecv,NULL,(void*)(&get_msg),&server_descriptor);
pthread_join(threadrecv,&retval);
pthread_join(threadsend,&retval);
//}
return 0;
}
服务器端:
#include <stdlib.h>
#include <stddef.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
typedef struct Msg {
int msg_type; //1 is request, 2 is answer
int msg_status;//0 is idle, 1 is busy
}MSG;
int main()
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
struct Msg Msg_respond;
int port = 4600;
char *recbuff = (char*)malloc(sizeof(MSG));
char *sendbuff = (char*)malloc(sizeof(MSG));
socklen_t len;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("Create socket failed!\n");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
if(bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != -1)
printf("Reday to receive!\n");
else
printf("failed\n");
for( ; ; )
{
len = (socklen_t)sizeof(cliaddr);
recvfrom(sockfd, recbuff, (int)sizeof(MSG), 0,(struct sockaddr*)&cliaddr, &len);
printf("shoudao\n");
//Msg_respond.msg_type = 2;
//Msg_respond.msg_status = 1;
Msg_respond = {2,1};
memcpy(sendbuff,(char*)&Msg_respond,(int)sizeof(Msg_respond));
sendto(sockfd, sendbuff, (int)sizeof(MSG), 0,(const struct sockaddr*)&cliaddr, len);
}
}
需要说明的是,我们在运行程序时,先运行服务器程序让其开始监听,然后再运行客户端程序。运行客户端程序时需要知道服务器端的ip地址,比如./client 192.168.1.1表示,我们运行可执行文件名为client的程序,并且所需通行的服务器端ip地址为192.168.1.1。因为在程序中
inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);
这段代码的含义就是要将运行时在命令行中输入的第一个字符串作为绑定serveraddr的ip地址。