對於socket網路程式設計,搗鼓了一週多,終於實現了電腦為服務端,學習板為客戶端之間的通訊
最開始是網上找到相關的客戶端,和服務端 的程式,然後試著去理解,但是這個過程很難過,因為從來沒有接觸過的,但是沒辦法,只能硬著頭皮啃,問老師,問學長,網上看視訊。終於是吧他啃下來了。
服務端的程式碼:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <malloc.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <stdarg.h> #include <fcntl.h> #include <fcntl.h> #include <sys/poll.h> #include <sys/epoll.h> #define BACKLOG 100 int main() { int iListenSock = socket(AF_INET, SOCK_STREAM, 0); //int socket(int domain, int type, int protocol);socket函式對應於普通檔案的開啟操作。普通檔案的開啟操作返回一個檔案描述字,而socket()用於建立一個socket描述符(socket descriptor),它唯一標識一個socket。這個socket描述字跟檔案描述字一樣,後續的操作都有用到它,把它作為引數,通過它來進行一些讀寫操作。 //1.協議族決定了socket的地址型別,在通訊中必須採用對應的地址,如AF_INET決定了要用ipv4地址(32位的)與埠號(16位的)的組合、AF_UNIX決定了要用一個絕對路徑名作為地址。 //2.type:指定socket型別。常用的socket型別有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等 //3.protocol故名思意,就是指定協議。常用的協議有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它們分別對應TCP傳輸協議、UDP傳輸協議、STCP傳輸協議、TIPC傳輸協議 sockaddr_in addr;// memset(&addr, 0, sizeof(addr)); inet_aton("192.168.1.66", &addr.sin_addr); //是一個改進的方法來將一個字串IP地址轉換為一個32位的網路序列IP地址。 /* struct sockaddr_in { unsigned short int sin_family;//協議族(family)連線方式 uint16_t sin_port;//定義埠號,可以直接指定,也可由系統指定,也是網路位元組序, 一般用htons()函式轉換。 struct in_addr sin_addr;//為ip地址,是二進位制的網路位元組序, 一般用inet_addr()函式完成轉換 unsigned char sin_zero[8];//一般不使用 } */ addr.sin_family = AF_INET;//協議族(family)採用IPv4網路協議 addr.sin_port = htons(8888);//伺服器監聽埠號 8888 int iOpt = 1; setsockopt(iListenSock, SOL_SOCKET, SO_REUSEADDR, &iOpt, sizeof(iOpt)); // 標配 bind(iListenSock, (sockaddr*)&addr, sizeof(addr));//bind()函式把一個地址族中的特定地址賦給socket。例如對應AF_INET、AF_INET6就是把一個ipv4或ipv6地址和埠號組合賦給socket。 listen(iListenSock, BACKLOG);//BACKLOG 100指定同時能夠處理的最大連線要求 epoll_event ev; ev.data.fd = iListenSock; ev.events = EPOLLIN; epoll_event events[BACKLOG + 1]; int epollFD = epoll_create(BACKLOG + 1); // 告訴核心監測的數目, 返回的epollFD為epoll管理控制代碼 epoll_ctl(epollFD, EPOLL_CTL_ADD, iListenSock, &ev); // 將ev和對應的iListenSock新增到epoll控制代碼,用於被epollFD管理 while(1) { int timeoutMS = -1; // 永不超時 int nfds = epoll_wait(epollFD, events, BACKLOG + 1, timeoutMS); // events和nfds是一對輸出值 printf("nfds is %d\n", nfds); for(int i = 0; i < nfds; i++) { if(events[i].data.fd == iListenSock) // 用於監聽客戶端連線的socket { int iConnSock = accept(iListenSock, NULL, NULL); if (iConnSock < 0) { continue; } ev.data.fd = iConnSock; ev.events = EPOLLIN; epoll_ctl(epollFD, EPOLL_CTL_ADD, iConnSock, &ev); // 將ev和對應的iConnSock新增到epoll控制代碼,用於被epollFD管理 printf("new sock came, fd is %d\n", iConnSock); } else { int iConnSock = events[i].data.fd; // 用於通訊的socket char szBuf[1024] = {0}; int recvLen = recv(iConnSock, szBuf, sizeof(szBuf) - 1, 0); if (recvLen > 0) { printf("recv data [%s] from fd [%d]\n", szBuf, iConnSock); } else if(0 == recvLen) { ev.data.fd = iConnSock; epoll_ctl(epollFD, EPOLL_CTL_DEL, iConnSock, &ev); close(iConnSock); printf("connection closed, local fd is [%d]\n", iConnSock); } else { ev.data.fd = iConnSock; epoll_ctl(epollFD, EPOLL_CTL_DEL, iConnSock, &ev); close(iConnSock); printf("recv error, local fd is [%d]\n", iConnSock); } } } } close(epollFD); close(iListenSock); return 0; }
雖然程式搞懂了,但是對於網路配置的,還是不懂,在其中遇到,PC,虛擬機器,板子的網路Ping通
主要問題如下
這個是因為程式裡面的IP地址不是你伺服器的地址,導致雖然在虛擬機器和板子網路可以ping得通,但是執行客戶端的程式沒有反應。解決方法,通過在虛擬機器輸入ifconfig 檢視IP地址。
接下來可能會出現接來的問題;
你發現你的Ip地址好像沒有,
這可能是你要去開啟你的網絡卡設定。
按照步驟走,IP可以自己選擇,也可以選擇自動,但是還是自己輸入比較好,因為要選擇跟板子上通一個網段。
我通過交叉編譯得到了板子上linux可執行程式,許多方便改變,這個也是一個大問題,我嘗試了很久通過NFS但是就是設定不好服務端的檔案。最後還是選擇了用u盤掛載,