用C說話停止最根本的socket編程。本站提示廣大學習愛好者:(用C說話停止最根本的socket編程)文章只能為提供參考,不一定能成為您想要的結果。以下是用C說話停止最根本的socket編程正文
甚麼是socket
你常常聽到人們議論著 “socket”,也許你還不曉得它切實其實切寄義。如今讓我告知你:它是應用 尺度Unix 文件描寫符 (file descriptor) 和其它法式通信的方法。甚麼?你或許聽到一些Unix高手(hacker)如許說過:“呀,Unix中的一切就是文件!”誰人家伙或許正在說到一個現實:Unix 法式在履行任何情勢的 I/O 的時刻,法式是在讀或許寫一個文件描寫符。一個文件描寫符只是一個和翻開的文件相干聯的整數。然則(留意前面的話),這個文件能夠是一個收集銜接,FIFO,管道,終端,磁盤上的文件或許甚麼其它的器械。Unix 中一切的器械就是文件!所以,你想和Internet上其余法式通信的時刻,你將要應用到文件描寫符。你必需懂得適才的話。如今你腦海中也許冒出如許的動機:“那末我從哪裡獲得收集通信的文件描寫符呢?”,這個成績不管若何我都要答復:你應用體系挪用 socket(),它前往套接字描寫符 (socket descriptor),然後你再經由過程它來停止send() 和 recv()挪用。“然則...”,你能夠有很年夜的困惑,“假如它是個文件描寫符,那末為什 麼不消普通挪用read()和write()來停止套接字通信?”簡略的謎底是:“你可使用!”。具體的謎底是:“你可以,然則應用send()和recv()讓你更好的掌握數據傳輸。”存在如許一個情形:在我們的世界上,有許多種套接字。有DARPA Internet 地址 (Internet 套接字),當地節點的途徑名 (Unix套接字),CCITT X.25地址 (你可以將X.25 套接字完整疏忽)。或許在你的Unix 機械上還有其它的。我們在這裡只講第一種:Internet 套接字。
Internet 套接字的兩品種型 :
甚麼意思?有兩品種型的Internet 套接字?是的。不,我在說謊。其實還有許多,然則我可不想嚇著你。我們這裡只講兩種。除這些, 我盤算別的引見的 "Raw Sockets" 也長短常壯大的,很值得查閱。
那末這兩品種型是甚麼呢?一種是"Stream Sockets"(流格局),別的一種是"Datagram Sockets"(數據包格局)。我們今後談到它們的時刻也會用到"SOCK_STREAM" 和 "SOCK_DGRAM"。數據報套接字有時也叫“無銜接套接字”(假如你確切要銜接的時刻可以用connect()。) 流式套接字是靠得住的雙向通信的數據流。假如你向套接字按次序輸入“1,2”,那末它們將按次序“1,2”達到另外一邊。它們是無毛病的傳遞的,有本身的毛病掌握,在此不評論辯論。
有甚麼在應用流式套接字?你能夠據說過 telnet,不是嗎?它就應用流式套接字。你須要你所輸出的字符按次序達到,不是嗎?異樣,WWW閱讀器應用的 HTTP 協定也應用它們來下載頁面。現實上,當你經由過程端口80 telnet 到一個 WWW 站點,然後輸出 “GET pagename” 的時刻,你也能夠獲得 HTML 的內容。為何流式套接字可以到達高質量的數據傳輸?這是由於它應用了“傳輸掌握協定 (The Transmission Control Protocol)”,也叫 “TCP” (請參考 RFC-793 取得具體材料。)TCP 掌握你的數據按次序達到而且沒有錯
誤。你或許聽到 “TCP” 是由於聽到過 “TCP/IP”。這裡的 IP 是指“Internet 協定”(請參考 RFC-791。) IP 只是處置Internet 路由罷了。
那末數據報套接字呢?為何它叫無銜接呢?為何它是弗成靠的呢?有如許的一些現實:假如你發送一個數據報,它能夠會達到,它能夠順序倒置了。假如它達到,那末在這個包的外部是無毛病的。數據報也應用 IP 作路由,然則它不應用 TCP。它應用“用戶數據報協定 (User Datagram Protocol)”,也叫 “UDP” (請參考 RFC-768。)
為何它們是無銜接的呢?重要是由於它其實不象流式套接字那樣保持一個銜接。你只需樹立一個包,結構一個有目的信息的IP 頭,然後收回去。無需銜接。它們平日應用於傳輸包-包信息。簡略的運用法式有:tftp, bootp等等。
你或許會想:“假設數據喪失了這些法式若何正常任務?”我的同伙,每一個法式在 UDP 上有本身的協定。例如,tftp 協定每收回的一個被接收到包,收到者必需發還一個包來講“我收到了!” (一個“敕令准確應對”也叫“ACK” 包)。假如在必定時光內(例如5秒),發送方沒有收到應對,它將從新發送,直到獲得 ACK。這一ACK進程在完成SOCK_DGRAM 運用法式的時刻異常主要。
簡略的發送和吸收完成
辦事器端吸收代碼:
#include <Winsock2.h> #pragma comment(lib,"Ws2_32.lib") #include <stdio.h> #include <memory.h> void main() { WSAData wsd; WSAStartup(MAKEWORD(2,0),&wsd); SOCKET s =NULL; s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); struct sockaddr_in ch; memset(&ch,0,sizeof(ch)); ch.sin_family=AF_INET; ch.sin_addr.s_addr=INADDR_ANY; ch.sin_port=htons(1041); int b=bind(s,(struct sockaddr *) &ch,sizeof(ch)); #define QUEUE_SIZE 5 int l=listen(s,QUEUE_SIZE); printf("正在監聽本機的1041端口!\n"); SOCKET sc=accept(s,0,0); printf("客戶端曾經銜接到本機的1041端口!\n"); #define BUF_SIZE 4096 int receByt=0; while(1) { char buf[BUF_SIZE]; receByt=recv(sc,buf,BUF_SIZE,0); buf[receByt]='\0'; if(receByt>0) { printf("吸收的新聞是:%s\n",buf); } else { printf("吸收新聞停止!"); break; } } int ic=closesocket(sc); int is=closesocket(s); }
客戶端發送的代碼:
#include <Winsock2.h> #pragma comment(lib,"Ws2_32.lib") #include <stdio.h> #include <memory.h> #include <string.h> void main() { WSAData wsd; WSAStartup(MAKEWORD(2,0),&wsd); SOCKET s =NULL; s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); struct sockaddr_in ch; memset(&ch,0,sizeof(ch)); ch.sin_family=AF_INET; ch.sin_addr.s_addr=inet_addr("127.0.0.1"); ch.sin_port=htons(1041); int c=connect(s,(struct sockaddr *) &ch,sizeof(ch)); printf("曾經銜接到辦事器的1041端口!如今可以向辦事器發送新聞了!\n"); #define BUF_SIZE 4096 char info[1024],buf[BUF_SIZE]; while(1) { gets(info); if(info[0]=='\0') break; strcpy(buf,info); int nsend=send(s,buf,strlen(buf),0); } int ic=closesocket(s); }
法式代碼經由了優化,而且整合多線程,把吸收和發送放到統一個文件中,應用參數形式挪用發送和吸收模塊。增長了創立SOCKET的創立的時刻s句柄(或對象)斷定前往值能否為INVALID_SOCKET,和socket的bind操作的前往值能否為SOCKET_ERROR,其他socket的操作應當也斷定SOCKET_ERROR,以包管法式的穩固性,這裡只是測試代碼就不去寫這麼多了,剩下的就由你小我施展。
#include <Winsock2.h> #pragma comment(lib,"Ws2_32.lib") #include <stdio.h> #include <memory.h> #include <string.h> #include <pthread.h> void Receive(); void Send(); void creatThread(); SOCKET s =NULL; pthread_t t[1000]; int threadCount=0; void main(int argc,char* argv[]) { printf("本法式制造人學號:713901040041\n"); printf("法式解釋:辦事器端和客戶端為統一個法式,請應用分歧的參數運轉.\n"); printf("吸收法式請應用 r參數;發送法式請應用 s參數。\n"); //printf("len : %d\n", argc); //printf("count %d\n",argc); //printf("value: %s\n",argv[1]); //printf("%d",argv[1][0]=='r'); if(argc<=1) { printf("please input program arguments ...\n"); exit(0); } if(argc>1 && argv[1][0]=='r') { printf("run receive ...\n"); Receive(); } if(argc>1 && argv[1][0]=='s') { printf("run send ...\n"); Send(); } } void* receiveWork(void * args) { SOCKET sc=accept(s,0,0); if(sc==INVALID_SOCKET) { printf("sc Error"); } creatThread(); printf("----------客戶端曾經銜接到本機的%d線程銜接!\n",threadCount-2); #define BUF_SIZE 4096 int receByt=0; while(1) { char buf[BUF_SIZE]; receByt=recv(sc,buf,BUF_SIZE,0); buf[receByt]='\0'; if(receByt>0) { printf("線程吸收的新聞是:%s\n",buf); } else { printf("客戶端已加入,"); break; } } int ic=closesocket(sc); printf("辦事器停止銜接!\n"); return NULL; } void creatThread() { pthread_create(&t[threadCount++],NULL,receiveWork,NULL); } void Receive() { WSAData wsd; WSAStartup(MAKEWORD(2,0),&wsd); s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(s==INVALID_SOCKET) { printf("socket created Error"); } struct sockaddr_in ch; memset(&ch,0,sizeof(ch)); ch.sin_family=AF_INET; ch.sin_addr.s_addr=INADDR_ANY; ch.sin_port=htons(1041); int b=bind(s,(struct sockaddr *) &ch,sizeof(ch)); if(b==SOCKET_ERROR) { printf("bind 掉敗,失足代碼是:%d\n",WSAGetLastError()); exit(0); } #define QUEUE_SIZE 5 int l=listen(s,QUEUE_SIZE); printf("正在監聽本機的1041端口!\n"); creatThread(); for(int i=0;i<1000;i++) { pthread_join(t[i],NULL); } int is=closesocket(s); } void Send() { WSAData wsd; WSAStartup(MAKEWORD(2,0),&wsd); SOCKET s =NULL; s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(s==INVALID_SOCKET) { printf("socket created Error"); } struct sockaddr_in ch; memset(&ch,0,sizeof(ch)); ch.sin_family=AF_INET; ch.sin_addr.s_addr=inet_addr("127.0.0.1"); ch.sin_port=htons(1041); int c=connect(s,(struct sockaddr *) &ch,sizeof(ch)); printf("曾經銜接到辦事器的1041端口!如今可以向辦事器發送新聞了!\n"); #define BUF_SIZE 4096 char info[1024],buf[BUF_SIZE]; while(1) { gets(info); if(info[0]=='\0') break; strcpy(buf,info); int nsend=send(s,buf,strlen(buf),0); } int ic=closesocket(s); }