欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

用C語言進(jìn)行最基本的socket編程

 更新時間:2015年11月19日 17:32:58   作者:jack_Meng  
這篇文章主要介紹了C語言下socket編程的基本知識講解,包括最基本的客戶端發(fā)送及服務(wù)器端接受數(shù)據(jù)的實(shí)現(xiàn),需要的朋友可以參考下

什么是socket
  你經(jīng)常聽到人們談?wù)撝?“socket”,或許你還不知道它的確切含義?,F(xiàn)在讓我告訴你:它是使用 標(biāo)準(zhǔn)Unix 文件描述符 (file descriptor) 和其它程序通訊的方式。什么?你也許聽到一些Unix高手(hacker)這樣說過:“呀,Unix中的一切就是文件!”那個家伙也許正在說到一個事實(shí):Unix 程序在執(zhí)行任何形式的 I/O 的時候,程序是在讀或者寫一個文件描述符。一個文件描述符只是一個和打開的文件相關(guān)聯(lián)的整數(shù)。但是(注意后面的話),這個文件可能是一個網(wǎng)絡(luò)連接,F(xiàn)IFO,管道,終端,磁盤上的文件或者什么其它的東西。Unix 中所有的東西就是文件!所以,你想和Internet上別的程序通訊的時候,你將要使用到文件描述符。你必須理解剛才的話?,F(xiàn)在你腦海中或許冒出這樣的念頭:“那么我從哪里得到網(wǎng)絡(luò)通訊的文件描述符呢?”,這個問題無論如何我都要回答:你利用系統(tǒng)調(diào)用 socket(),它返回套接字描述符 (socket descriptor),然后你再通過它來進(jìn)行send() 和 recv()調(diào)用?!暗?..”,你可能有很大的疑惑,“如果它是個文件描述符,那么為什 么不用一般調(diào)用read()和write()來進(jìn)行套接字通訊?”簡單的答案是:“你可以使用!”。詳細(xì)的答案是:“你可以,但是使用send()和recv()讓你更好的控制數(shù)據(jù)傳輸?!贝嬖谶@樣一個情況:在我們的世界上,有很多種套接字。有DARPA Internet 地址 (Internet 套接字),本地節(jié)點(diǎn)的路徑名 (Unix套接字),CCITT X.25地址 (你可以將X.25 套接字完全忽略)。也許在你的Unix 機(jī)器上還有其它的。我們在這里只講第一種:Internet 套接字。
Internet 套接字的兩種類型 :
  什么意思?有兩種類型的Internet 套接字?是的。不,我在撒謊。其實(shí)還有很多,但是我可不想嚇著你。我們這里只講兩種。除了這些, 我打算另外介紹的 "Raw Sockets" 也是非常強(qiáng)大的,很值得查閱。
那么這兩種類型是什么呢?一種是"Stream Sockets"(流格式),另外一種是"Datagram Sockets"(數(shù)據(jù)包格式)。我們以后談到它們的時候也會用到"SOCK_STREAM" 和 "SOCK_DGRAM"。數(shù)據(jù)報套接字有時也叫“無連接套接字”(如果你確實(shí)要連接的時候可以用connect()。) 流式套接字是可靠的雙向通訊的數(shù)據(jù)流。如果你向套接字按順序輸出“1,2”,那么它們將按順序“1,2”到達(dá)另一邊。它們是無錯誤的傳遞的,有自己的錯誤控制,在此不討論。
    有什么在使用流式套接字?你可能聽說過 telnet,不是嗎?它就使用流式套接字。你需要你所輸入的字符按順序到達(dá),不是嗎?同樣,WWW瀏覽器使用的 HTTP 協(xié)議也使用它們來下載頁面。實(shí)際上,當(dāng)你通過端口80 telnet 到一個 WWW 站點(diǎn),然后輸入 “GET pagename” 的時候,你也可以得到 HTML 的內(nèi)容。為什么流式套接字可以達(dá)到高質(zhì)量的數(shù)據(jù)傳輸?這是因?yàn)樗褂昧恕皞鬏斂刂茀f(xié)議 (The Transmission Control Protocol)”,也叫 “TCP” (請參考 RFC-793 獲得詳細(xì)資料。)TCP 控制你的數(shù)據(jù)按順序到達(dá)并且沒有錯
誤。你也許聽到 “TCP” 是因?yàn)槁牭竭^ “TCP/IP”。這里的 IP 是指“Internet 協(xié)議”(請參考 RFC-791。) IP 只是處理Internet 路由而已。
    那么數(shù)據(jù)報套接字呢?為什么它叫無連接呢?為什么它是不可靠的呢?有這樣的一些事實(shí):如果你發(fā)送一個數(shù)據(jù)報,它可能會到達(dá),它可能次序顛倒了。如果它到達(dá),那么在這個包的內(nèi)部是無錯誤的。數(shù)據(jù)報也使用 IP 作路由,但是它不使用 TCP。它使用“用戶數(shù)據(jù)報協(xié)議 (User Datagram Protocol)”,也叫 “UDP” (請參考 RFC-768。)
    為什么它們是無連接的呢?主要是因?yàn)樗⒉幌罅魇教捉幼帜菢泳S持一個連接。你只要建立一個包,構(gòu)造一個有目標(biāo)信息的IP 頭,然后發(fā)出去。無需連接。它們通常使用于傳輸包-包信息。簡單的應(yīng)用程序有:tftp, bootp等等。
    你也許會想:“假如數(shù)據(jù)丟失了這些程序如何正常工作?”我的朋友,每個程序在 UDP 上有自己的協(xié)議。例如,tftp 協(xié)議每發(fā)出的一個被接受到包,收到者必須發(fā)回一個包來說“我收到了!” (一個“命令正確應(yīng)答”也叫“ACK” 包)。如果在一定時間內(nèi)(例如5秒),發(fā)送方?jīng)]有收到應(yīng)答,它將重新發(fā)送,直到得到 ACK。這一ACK過程在實(shí)現(xiàn)SOCK_DGRAM 應(yīng)用程序的時候非常重要。

簡單的發(fā)送和接收實(shí)現(xiàn)

服務(wù)器端接收代碼:

#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("正在監(jiān)聽本機(jī)的1041端口!\n");
SOCKET sc=accept(s,0,0);
printf("客戶端已經(jīng)連接到本機(jī)的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("接收消息結(jié)束!");
break;
}

}
int ic=closesocket(sc);
int is=closesocket(s);

}

客戶端發(fā)送的代碼:

#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("已經(jīng)連接到服務(wù)器的1041端口!現(xiàn)在可以向服務(wù)器發(fā)送消息了!\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);
}

程序代碼經(jīng)過了優(yōu)化,并且整合多線程,把接收和發(fā)送放到同一個文件中,使用參數(shù)模式調(diào)用發(fā)送和接收模塊。增加了創(chuàng)建SOCKET的創(chuàng)建的時候s句柄(或?qū)ο螅┡袛喾祷刂凳欠駷镮NVALID_SOCKET,以及socket的bind操作的返回值是否為SOCKET_ERROR,其他socket的操作應(yīng)該也判斷SOCKET_ERROR,以保證程序的穩(wěn)定性,這里只是測試代碼就不去寫這么多了,剩下的就由你個人發(fā)揮。

#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("本程序制作人學(xué)號:713901040041\n");
  printf("程序說明:服務(wù)器端和客戶端為同一個程序,請使用不同的參數(shù)運(yùn)行.\n");
  printf("接收程序請使用 r參數(shù);發(fā)送程序請使用 s參數(shù)。\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("----------客戶端已經(jīng)連接到本機(jī)的%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("服務(wù)器結(jié)束連接!\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("正在監(jiān)聽本機(jī)的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("已經(jīng)連接到服務(wù)器的1041端口!現(xiàn)在可以向服務(wù)器發(fā)送消息了!\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);
}

相關(guān)文章

  • C++內(nèi)存管理介紹

    C++內(nèi)存管理介紹

    這篇文章主要介紹了C++內(nèi)存管理,C++標(biāo)準(zhǔn)委員會給我們提供了auto_ptr智能指針,后面又引入了share_ptr以及weak_ptr幫助我們正確和安全的使用指針,本文主要是介紹boost庫提供的解決方案,需要的朋友可以參考一下
    2022-01-01
  • C++利用鏈棧實(shí)現(xiàn)表達(dá)式求值

    C++利用鏈棧實(shí)現(xiàn)表達(dá)式求值

    這篇文章主要為大家詳細(xì)介紹了C++利用鏈棧實(shí)現(xiàn)表達(dá)式求值的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-05-05
  • C++實(shí)現(xiàn)LeetCode(87.攪亂字符串)

    C++實(shí)現(xiàn)LeetCode(87.攪亂字符串)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(87.攪亂字符串),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 使用?c++?在?windows?上定時執(zhí)行一個函數(shù)的示例代碼

    使用?c++?在?windows?上定時執(zhí)行一個函數(shù)的示例代碼

    這篇文章主要介紹了使用c++在windows上穩(wěn)定定時執(zhí)行一個函數(shù),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • windows上安裝CLion教程及簡單使用詳解

    windows上安裝CLion教程及簡單使用詳解

    這篇文章主要介紹了windows上安裝CLion教程及簡單使用,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • C語言中static的使用介紹

    C語言中static的使用介紹

    大家好,本篇文章主要講的是C語言中static的使用介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • C++ 命名空間--namespace總結(jié)

    C++ 命名空間--namespace總結(jié)

    namespace中文意思是命名空間或者叫名字空間,下面這篇文章主要給大家介紹了關(guān)于C++中名稱空間namespace使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧
    2021-09-09
  • C語言入門篇--學(xué)習(xí)選擇,if,switch語句以及代碼塊

    C語言入門篇--學(xué)習(xí)選擇,if,switch語句以及代碼塊

    本篇文章是基礎(chǔ)篇,適合c語言剛?cè)腴T的朋友,本文主要帶大家學(xué)習(xí)一下C語言的選擇,if,switch語句及代碼塊,幫助大家快速入門c語言的世界,更好的理解c語言
    2021-08-08
  • C語言實(shí)現(xiàn)簡易文本編譯器

    C語言實(shí)現(xiàn)簡易文本編譯器

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡易文本編譯器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • C++模板實(shí)現(xiàn)順序棧

    C++模板實(shí)現(xiàn)順序棧

    這篇文章主要為大家詳細(xì)介紹了C++模板實(shí)現(xiàn)順序棧,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04

最新評論