分享

网络编程2

 云中虾 2016-10-19









一 UDP通信框架


UDPSend.c

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(int arg, char *args[]) { if (arg < 3) return -1; int st = socket(AF_INET, SOCK_DGRAM, 0);//建立socket的时候第二个参数值为SOCK_DGRAM if (st == -1) { printf('socket failed %s\n', strerror(errno)); return 0; } int port = atoi(args[2]); int on = 1; if (setsockopt(st, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1)//设置UDP socket可以发送广播消息 { printf('setsockopt failed %s\n', strerror(errno)); return EXIT_FAILURE; } struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(args[1]); char buf[1024]; while (1) { memset(buf, 0, sizeof(buf)); read(STDIN_FILENO, buf, sizeof(buf));//读取用户键盘输入 if (sendto(st, buf, strlen(buf), 0, (struct sockaddr *) &addr, sizeof(addr)) == -1)//udp使用sendto发送消息 { printf('sendto failed %s\n', strerror(errno)); break; } } close(st); return EXIT_SUCCESS; }

UDPRecv.c

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(int arg, char *args[]) { if (arg < 2) return -1; int st = socket(AF_INET, SOCK_DGRAM, 0); if (st == -1) { printf('socket failed %s\n', strerror(errno)); return 0; } int port = atoi(args[1]); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(st, (struct sockaddr *)&addr, sizeof(addr)) == -1)//UDP接收数据,也需要绑定IP,不需要监听和connnect { printf('bind failed %s\n', strerror(errno)); return -1; } char buf[1024]; struct sockaddr_in client_addr; socklen_t len = sizeof(client_addr); while (1) { memset(&client_addr, 0, sizeof(client_addr)); memset(buf, 0, sizeof(buf)); if (recvfrom(st, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &len) == -1) { printf('recvfrom failed %s\n', strerror(errno)); break; } else { printf('%s recv is %s\n', inet_ntoa(client_addr.sin_addr), buf); } } close(st); return 0; }

makefile文件

.SUFFIXES:.c .o CC=gcc SRCS1=udpsend.c SRCS2=udprecv.c OBJS1=$(SRCS1:.c=.o) OBJS2=$(SRCS2:.c=.o) EXEC1=udprecv EXEC2=udpsend start:$(OBJS2) $(OBJS1) $(CC) -o $(EXEC2) $(OBJS2) -lpthread $(CC) -o $(EXEC1) $(OBJS1) -lpthread @echo '======OK!=========\n' .c.o: $(CC) -o $@ -c $< clean: rm -r $(OBJS2) $(EXEC2) $(EXEC1) $(OBJS1)


二 UDP文件传输系统


client.c
#include <stdio.h> #include <stdlib.h> #include 'pub.h' int main(int arg, char *args[]) { if (arg < 4)//如果参数小于3个,main函数退出 { printf('Input argumnet: source | IP | Port | resource\n'); return EXIT_FAILURE; } int iport = atoi(args[2]);//将第二个参数转化为端口号 if (iport == 0)//如果端口号为0,main函数退出 { printf('port %d is invalid\n', iport); return EXIT_FAILURE; } printf('%s send begin\n', args[3]); if (send_work(args[1], iport, args[3]) == 1) printf('%s send success\n', args[3]); else printf('%s send fail\n', args[3]); return EXIT_SUCCESS; }

server.c
#include <stdio.h> #include <stdlib.h> #include 'pub.h' int main(int arg, char *args[]) { if (arg < 2)//如果没有参数,main函数退出 { printf('Input like: source | port\n'); return EXIT_FAILURE; } int iport = atoi(args[1]);//将第一个参数转化为端口号,server端socket要在这个端口号上listen if (iport == 0) { printf('port %d is invalid\n', iport); return EXIT_FAILURE; } printf('recv is begin\n'); if (recv_work(iport) == 1)//server端socket在port指定的端口上listen,接收来自client发送的文件 printf('recv success\n'); else printf('recv fail\n'); return EXIT_SUCCESS; }

pub.h
#ifndef PUB_H_ #define PUB_H_ int send_work(const char *hostname, int port, const char *filename); int recv_work(int port); #endif

pub.c
#ifdef WIN #include <WinSock2.h> #else #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <errno.h> #include <string.h> #define SOCKET int #endif #include <stdio.h> #include 'pub.h' #define BUFSIZE 262144 //256k void getfilename(const char *filename, char *name)//从完整路径名中解析出文件名称,例如:/home/test/abc.txt,解析完成后为abc.txt { int len = strlen(filename); int i; for (i = (len - 1); i >= 0; i--) { if ((filename[i] == '\\') || (filename[i] == '/')) { break; } } strcpy(name, &filename[i 1]); return; } SOCKET init_socket()//初始化socket { //如果是windows,执行如下代码 #ifdef WIN WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return -1; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return -1; } #endif return 0; } SOCKET create_recv_socket(int port)//在port指定的端口上建立接收数据的IDP SOCKET { //if (init_socket() == -1) //return; SOCKET st = socket(AF_INET, SOCK_DGRAM, 0);//建立socket的时候第二个参数值为SOCK_DGRAM if (st == 0) return 0;//失败,返回0 struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(INADDR_ANY); if (bind(st, (struct sockaddr *)&addr, sizeof(addr)) == -1)//UDP接收数据,也需要绑定IP,不需要监听和connnect { printf('bind failed %s\n', strerror(errno)); return 0; } return st; } SOCKET create_send_socket()//建立发送数据的UDP Socket { if (init_socket() == -1) return; SOCKET st = socket(AF_INET, SOCK_DGRAM, 0);//建立socket的时候第二个参数值为SOCK_DGRAM if (st == 0) return 0;//失败,返回0 return st;//成功 } int send_work(const char *hostname, int port, const char *filename)//向hostname指定的IP地址发送filename指定的文件 { SOCKET st_send = create_send_socket();//建立发送数据的UDP Socket SOCKET st_recv = create_recv_socket(port 1);//建立接收数据的UDP Socket if (st_send == 0)//建立失败,函数返回 return 0; if (st_recv == 0) return 0; FILE *fd = fopen(filename, 'rb');//以只读方式打开filename指定的文件 if (fd == NULL)//如果文件打开失败,函数返回 { printf('open %s failed %s\n', filename, strerror(errno)); return 0; } char *buf = malloc(BUFSIZE);//申请一个缓冲区,存放接收到的文件内容 memset(buf, 0, BUFSIZE); getfilename(filename, buf);//从完整路径名中解析出文件名称,例如:/home/test/abc.txt,解析完成后为abc.txt struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(hostname); size_t rc = sendto(st_send, buf, strlen(buf), 0, (struct sockaddr *) &addr,sizeof(addr));//客户端第一次给server端发送的数据为要传递的文件名称,将解析完成后的文件名通过socket发送给server端 if (rc <= 0)//发送失败 { printf('send failed %s\n', strerror(errno)); } else //发送成功 { struct sockaddr_in client_addr; #ifdef WIN int len = 0; #else unsigned int len = 0; #endif len = sizeof(client_addr); memset(&client_addr, 0, sizeof(client_addr)); memset(buf, 0, BUFSIZE); if (recvfrom(st_recv, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &len) <= 0)//接收来自server端的回复 { printf('recv failed %s\n', strerror(errno)); } else { if (strncmp(buf, 'OK', 2) == 0)//如果收到来自服务端的回复,代表服务端认可,可以发送文件了 { while (1) { memset(buf, 0, BUFSIZE); rc = fread(buf, 1, BUFSIZE, fd);//循环读取文件,直到读到文件尾,循环break if (rc <= 0) { break;//如果到文件最后,循环终止 } else { rc = sendto(st_send, buf, rc, 0, (struct sockaddr *) &addr, sizeof(addr));//将从文件中读到的数据,通过socket发送到server端,其中rc为从文件中读到的数据大小 if (rc <= 0)//如果发送失败,代表TCP连接出错,循环break { printf('send failed %s\n', strerror(errno)); } } } } memset(buf, 0, BUFSIZE); rc = sendto(st_send, buf, 128, 0, (struct sockaddr *) &addr, sizeof(addr));//连续发送128个0字节,代表文件发送完毕 } } fclose(fd); free(buf); #ifdef WIN closesocket(st_send); closesocket(st_recv); WSACleanup(); #else close(st_send); close(st_recv); #endif return 1; } int recv_work(int port)//server端socket在port指定的端口上listen,接收来自client发送的文件 { SOCKET st_send = create_send_socket();//建立发送数据的UDP Socket SOCKET st_recv = create_recv_socket(port 1);//建立接收数据的UDP Socket if (st_send == 0)//建立失败,函数返回 return 0; if (st_recv == 0) return 0; char *buf = malloc(BUFSIZE);//建立接收文件数据缓冲区 FILE *fd = NULL; #ifdef WIN int len = 0; #else unsigned int len = 0; #endif struct sockaddr_in client_addr; len = sizeof(client_addr); memset(&client_addr, 0, len); memset(buf, 0, BUFSIZE); size_t rc = recvfrom(st_recv, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &len);//接收来自client的数据,客户端第一次要发送的文件名称 if (rc <= 0) { printf('recv failed %s\n', strerror(errno)); } else { printf('receiving %s\n', buf); fd = fopen(buf, 'wb');//以只写方式打开文件 if (fd == NULL) { printf('open %s failed %s\n', buf, strerror(errno)); } else { client_addr.sin_port = htons(port 1);//客户端接收的端口号 memset(buf, 0, BUFSIZE); strcpy(buf, 'OK'); rc = sendto(st_send, buf, strlen(buf), 0, (struct sockaddr *) &client_addr, sizeof(client_addr));//回复客户端,同意接收文件 if (rc <= 0) { printf('send failed %s\n', strerror(errno)); } while (1) { memset(buf, 0, BUFSIZE); rc = recvfrom(st_recv, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &len);//循环接收来自client的数据,数据为发送文件的内容 char tmp[128]; memset(tmp, 0, 128); if (memcmp(buf, tmp, sizeof(tmp)) == 0)//连续接收到128Z字节的0,结束 break; if (rc <= 0)//如果client连接断开,代表文件传递完成,或者网络意外中断,循环break { printf('recv failed %s\n', strerror(errno)); break; } else { fwrite(buf, 1, rc, fd);//将从client端收到的内容写入文件 } } } } if (fd) fclose(fd);//关闭打开的文件 free(buf); #ifdef WIN closesocket(st_send); closesocket(st_recv); WSACleanup(); #else close(st_send); close(st_recv); #endif return 1; }

makefile
.SUFFIXES:.c .o CC=gcc SRCS1=client.c pub.c SRCS2=server.c pub.c OBJS1=$(SRCS1:.c=.o) OBJS2=$(SRCS2:.c=.o) EXEC1=client EXEC2=server start:$(OBJS2) $(OBJS1) $(CC) -o $(EXEC2) $(OBJS2) -lpthread $(CC) -o $(EXEC1) $(OBJS1) -lpthread @echo '======OK!=========\n' .c.o: $(CC) -o $@ -c $< clean: rm -r $(OBJS2) $(EXEC2) $(EXEC1) $(OBJS1)




    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约