2015年10月14日 星期三

Link-level Measurements from an 802.11b Mesh Network

Link-level Measurements from an 802.11b Mesh Network
   這篇paper主要在38-node unban multi-hop 802.11b network下,分析封包遺失的原因,這個networkCambridge Massachusetts,範圍包含六千平方公尺,每一個node代表一棟上面裝有omni-directional antenna的房子。利用Distribution of Delivery Probabilities去分析影響packet loss的原因,主要探討的因素依序為Time Variation of Loss RateEffect of Signal-to-Noise RatioEffect of Transmit Bit-RateInterference from 802.11 SourcesEffect of Multi-path
Time Variation of Loss Rate:
   有四條delivery probabilities 50% link被選出來做為Time Variation of Loss Rate的分析,如圖一,圖越下面variation越小。這邊的deviation計算利用Allan deviation= ,圖二為這四條link在不同時間間隔所計算出的Allan deviation,可以發現時間間隔越大,Allan deviation會被平滑的越小。圖三是ALL LINKAllan Deviation of Loss Rate的累積圖表,可以發現High Deviation of Loss Rate占的比率很少,說明大部分的Loss Rate都是穩定的。

                                                                              圖一                    
                                                                                                                                                       圖二                    
                                                                                                                                                      圖三
Effect of Signal-to-Noise Ratio:
   The Prism 2.5 specificationpacket error rate 介於10% and 90%時,range of S/N 3dB。圖四,是由模擬器所模擬出S/NDelivery Probability的影響。說明S/N對於Delivery Probability有正向的作用,但由圖五在dB>3的情況下,還是有蠻多的packet的情況出現,說明S/N不是造成packet loss的唯一因素。
                                                                                    圖四                       
                                                                                                                                                        圖五
Effect of Transmit Bit-Rate:
   圖六代表每一個link在不同的transmit bit-ratethroughput,由這個圖可以發現link11Mbit/s,儘管他的loss rate5.5Mbit/s還高,但是throughput卻比較高,但這也不代表高的11Mbit/s就擁有高的throughput,還是不少1Mbit/Slinkthroughput11Mbit/s還要多。由以上的現象我們可以觀察到,bit-rate的選擇不能直接地去預測,而是必須徹底在每一個bit-rate去測量他的throughput

                                                                                    圖六
Interference from 802.11 sources
    這邊在探討在同一個channel或是overlapping channel發送不是roofnet的封包(Foreign Packets),是否會影響RoofnetLoss Rate,由實驗發現答案是不會的,由圖七可以發現,Foreign Packets/Second的大小並沒有和Lost Packets/Second有任何明顯的相關性。
                                                                                 圖七
Effect of multi-path:
  這一個接收系統可以分辯出到達時間差小於250nanoseconds original signal reflected signal,所以只要時間差小於250 nanoseconds就對original的接收不會造成太大的影響,但在實際上reflect signaldelay大都大於microsecond。以圖八來看說明reflected sign確實造成了packet loss這是一個two-ray的模擬情況,這個例子傳輸速率是1Mbps,在Delay1 microseconds下,模擬出的reflected signal被衰減9dB,造成10%packet loss rate,率減為7dB則造成90%packet loss rate但我們也可以發現只要delay時間夠小,reflected signal其實不會對original signal造成什麼影響,接下要問那什麼會影響delay的時間,答案是可以說是傳輸距離,雖然他不是直接的原因,但因為傳輸距離夠長,就可以產生足夠長的delay去影響original signal的接收。由圖九可以看出傳輸距離愈長,則delivery probabilities愈小。

                                                                              圖八
                                                                              圖九

這篇PAEPERroofnetnetwork下探討了許多影響傳輸的原因,S/N和傳輸的距離確實會造成一些影響,但是卻不是主要或是直接的因素,主要的因素在於multi-path fading,因此在一個城市裡roofnet networkmulti-path是非常需要去解決的問題。

Capacity of Ad Hoc Wireless Networks - Junyang Li , Charles Blake , Douglas S.J. De Couto , Hu lmm Lee , Robert Morris

Capacity of Ad Hoc Wireless Networks

1.Introduction:

    因為空間頻譜的再利用,可預期Ad Hoc 網路的總容量可增大到覆蓋該區域面積。然而,ad hoc的路由機制需要節點間的合作來相互傳送其他node的封包,這樣使得每個node不只受限於raw channel capacity還有遠方node帶來的forwarding load,這嚴重影響了ad hoc的路由路徑。
    根據Gupta 和 Kumar的分析,total one hop的capacity約等於O(n*n^(1/2)),每個節點的end-to-end throughput約等於O(1/n(^1/2)),n為節點個數,所以當節點數不斷的增加,throughput會接近"0",這是因為這簡單的分析省略了用來判斷是否有任何影響特定單一節點的網路吞吐量常數。
    因為限制容量的因素,ad hoc傾向於使用low data rate。本篇paper中使用Interaction between ad hoc forwarding and 802.11MAC和impact of communication來了解應用在實際網路的可行性。

2. 802.11Background

    To reduce collisions caused by hidden terminals [1] in the network, 802.11 uses a four-way RTS/CTS/Data/Ack exchange.
RTS/CTS 機制是基於CSMA/CA 協定上,所提出改善隱藏節點問題的機制。 原本CSMA/CA機制資料的傳送,僅需用到Data 及 ACK,發送端傳Data,接收端收到後回覆ACK。 而啟用RTS/CTS 機制後,則是發送端先送RTS 提出請求,接收端回覆CTS,前兩步驟用意就是在確認傳輸用通道,及通知週遭節點 Freeze Backoff time,用意就是避免碰撞及干擾。 完成後發送端才傳送Data,接收端回ACK。 
    Each node uses these times to update its “network allocation vector” (NAV). The NAV value indicates the amount of time remaining before the network will become available.

NAV是避免其他站台傳給正在傳送中的兩台站台,RTS/CTS是無法避免COLLISION,因為還是有可能會同時多台同時送RTS/CTS而發生RTS/CTS COLLISION ,RTS/CTS是很小的所以發生碰撞比傳送中的資料(DATA封包>>RTS/CTS)發生碰撞還要省時間NAV是避=免傳送中的兩台站台的範圍內的其他站在暫停去送,DATA給正在傳送中的站台

3.MAC interactions

本篇paper使用的ns模擬器data rate為2M bps,傳輸有效範圍為200m,干擾範圍為550m,節點之間距離為200m。

Single Cell Capacity:

每個節點都是src,隨機選一個dst傳送,因為2-node的狀況下沒有其他node的干擾,capacity可達到最大,因RTS/CTS,header的影響,最大的吞吐量約等於1.7Mbps。


Capacity of a Chain of Nodes:

因不能同時接收/傳送,node1、2與node1、3不可同時傳送,只有node1、4可以同時傳送,這使得chain utilization只有1/3,又因為傳輸範圍<干擾範圍,node4的資料傳輸會干擾到node1、2的RTS/CTS,所以chain utilization降為1/4,實際模擬最大的吞吐量為4.1Mbps約等於1/4。但是,當chain夠長的時候,offered load increase > optimum,吞吐量會急速下降到1/7,這是因為chain中間的node受到的干擾比第一個node還大,沒辦法跟上第一個node傳來的data,導致吞吐量的下降。

Capacity of a Regular Lattice Network:

左圖為horizontal,每個node流量從左到右,每當第三條chain激活時,其垂直干擾可能達到550m,在iner-flow的影響下,每個flow的吞吐量會降至1/12;右圖為horizontal and vertical,每個node的流量為左到右,上到下,每個node都有一個Queue,這會讓node再傳送水平封包時會失去傳送垂直封包的機會,增加的back-off使得吞吐量下降,根據模擬出的結果,其吞吐量比預期的還低。

Random Traffic in a Random Layout:

node隨機均勻分布,每個node都是src並隨機挑選dst點然後計算最短路徑,因不規則的放置node導致浪費空間,進而浪費容量,隨機選擇dst也導致更多的packet通過網路的中心部分,使得整體的capacity由中心來控制,然而,Lattice的分布是相對勻稱的。

4.Scaling Ad Hoc Network:

比較一個大型的網路capacity與node的loading,估計bandwidth使每個node可預測自己的traffic。
one-hop capacity取決於整個網路的頻寬再利用量,在固定射頻範圍R,空間再利用率與網路實際面積成正比,假設node密度為d,網路實際面積為A,n為node數,A=n/d,整個網路的capacity為C,可得C = kA=k*n/d,封包hop數L/R,封包速率V,所以C<n*V*L/R。

可知路徑長度增加,每個節點的Badwidth也會增加,所以這對ad hoc網路擴充性有很大的影響。

Random traffic pattern:

假設每個node的機率皆相同,且個別的節點capacity可達到O(1/n^(1/2)),固定的傳輸範圍,獨立網路大小,且網路增大時預設路徑長度也固定,使每個node的capacity都固定。

5.Conclusion:

當網路增大時,802.11 MAC interaction forwarding對capacity及node的scalability是有影響的,而在long chain中,因greedy sender導致吞吐量下降,所以發現在traffic pattern中隨機流量分布模式可以使得每個node的capacity接近理論值O(1/n(^1/2))













2015年10月11日 星期日

Concurrent TCP server網路程式設計(2):

  在Linux中,網路程式設計主要全靠socket來接收及傳送資料,本次我們要探討多個client端連接至一台伺服器的情形。
  若要讓TCP server同時處理多個client的連線,最簡單的方法便是使用concurrent TCP server架構(如下圖)。






















Concurrent TCP server 架構:

  所謂的[Concurrent TCP server]架構,是由父程序產生多個子程序,每個子程序分別與建立連線的client端進行資料傳輸,在傳輸的過程中,父程序只負責連線的接收,每次連線成功便產生對應的子程序。

如何產生子程序?

  我們可以讓server呼叫 fork() 函數來產生子程序,  fork() 函數會將新建立的通訊端複製到子程序中,在子程序中可以與連上的client端進行通訊。


  一個concurent TCP server的基礎程式架構如下。

--------------------------------------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
  int len_inet;
  struct sockaddr_in adr_srvr,adr_clnt;
  pid_t PID;

  /*建立listening socket*/

  sockfd = socket(AF_INET,SOCK_STREAM,0);

  /*連結socket*/

  bind(sockfd,(struct sockaddr*)&adr_srvr,sizeof(adr_srvr));

  /*傾聽client*/

  listen(sockfd,10);

  while(1)
  {
     len_inet = sizeof(adr_clnt);

     /*接受client端連線請求,建立connected socket*/

     connfd = accept(sockfd, (struct sockaddr *)&adr_clnt, &len_inet);

    /*建立子程序*/

    PID = fork();
    if(PID>0)
     {
        /*父程序關閉connected socket*/
        
        close(connfd);

        /*返回while開頭*/
        
        continue;
     }
    printf("子程序處理....\n");

    /*子程序關閉listening socket*/

    close(sockfd);

    /*與連線client端進行資料傳輸*/
  
    exit(0);
  }
 return 0;
}
-------------------------------------------------------------------------------------------------------------------

由上述的基礎程式架構,可以發現建構concurrent TCP server的一些原則:

1. 在呼叫fork()函數前,我們必須呼叫socket()、bind()、listen()與accept(),來建立listening socket(sockfd),以接收來自client端的連線請求
2. 當server接受client端的連線請求時,會傳回connected socket(connfd)
3. 在呼叫fork()後,若為父程序,則關閉connected socket,回到while迴圈的起始點,等待另一個client端的請求。
4. 在呼叫 fork() 後,若為子程序,則關閉listening socket,並與連線的client端進行資料的輸出輸入,完畢後結束程序,並回傳 0。


注意Zombie程序:

  當在設計這種concurrent TCP server架構時,由於我們會使用fork()函數,子程序在呼叫exit()結束後,會進入zombie程序,若父程序不處理這些zombie程序,便會常駐在記憶體中,最後會拖垮整個系統的效率!
  所以我們可以在建立子程序時,透過接受SIGCHILD訊息,撰寫相關的訊息處理函數,一個SIGCHILD訊息處理函數程式碼如下。
-------------------------------------------------------------------------------------------------------------------
static void sigchld_handler() {
  pid_t PID;
  int status;

  while (PID = waitpid(-1, &status, WNOHANG) > 0)
 printf("子程序 %d 結束.\n", PID);

  /* Re-install handler */
  signal(SIGCHLD, sigchld_handler);
}
------------------------------------------------------------------------------

上述程式碼呼叫了 waitpid()函數來清除zombie程序,waitpid()函數的第一個引數為[-1],表示等待任何子程序,第二個引數用來儲存子程序結束的狀態,第三個引數設為[WNOHANG],表示當沒有任何zombie程序時,馬上返回,不予等待。

由上述的介紹後,我們還練習撰寫一個網路多工的程式。

動作要求:

1. server程式在執行後,可以接受多個client的連線要求。
2. server程式會在client端連線後,以每隔一秒的時間,將目前的系統時間傳送至client端
3. client端會接收server端傳來的訊息,並將訊息顯示出來。

程式:server端

/* multi_server2.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

static void sigchld_handler() {
  pid_t PID;
  int status;

  while (PID = waitpid(-1, &status, WNOHANG) > 0)
 printf("子程序 %d 結束.\n", PID);

  /* Re-install handler */
  signal(SIGCHLD, sigchld_handler);
}

int main(int argc, char **argv) {
  int  z, len_inet;
  struct sockaddr_in adr_srvr, adr_clnt;
  int  sockfd, connfd;
  pid_t  PID;
  time_t clock;
  struct tm *tm;
  int  len_time, i;
  char  buf[256];
  
  signal(SIGCHLD, sigchld_handler);
  
  memset(&adr_srvr, 0, sizeof(adr_srvr));
  
  if (argc ==2)
 adr_srvr.sin_addr.s_addr = inet_addr(argv[1]);
  else
 adr_srvr.sin_addr.s_addr = inet_addr("192.168.1.20");
  

  adr_srvr.sin_family = AF_INET;
  adr_srvr.sin_port = htons(9090);
 
  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd == -1) {
 perror("socket error");
 exit(1);
  }

  z = bind(sockfd, (struct sockaddr *)&adr_srvr, sizeof(adr_srvr));
  if (z == -1) {
 perror("bind error");
 exit(1);
  }

  z = listen(sockfd, 10);
  if (z == -1) {
 perror("listen error");
 exit(1);
  }

  while(1) {
 len_inet = sizeof(adr_clnt);
 connfd = accept(sockfd, (struct sockaddr *)&adr_clnt, &len_inet);
 if (connfd == -1) {
  perror("connect error");
  exit(1);
 }
 
 PID = fork();

 if (PID > 0) {
  close(connfd);
  continue;
 }

 printf("子程序處理...\n");
 close(sockfd);
 for (i=0; i<10; i++) {
  sleep(1);
  time(&clock);
  tm = gmtime(&clock);
  len_time = strftime(buf, 256, "%A %T %D\n", tm);
 
  if (write(connfd, buf, len_time) == -1) {
   perror("write error");
   exit(1);
  }
 }
 sleep(1);
 sprintf(buf, "stop\n");
 write(connfd, buf, sizeof(buf));
 exit(0);
  }
  return 0;
}

程式:client端

/* multi_client.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

int main(int argc, char **argv) {
  int z, len_inet;
  struct sockaddr_in adr_srvr;
  int sockfd;
  int i;
  char buf[256];
  
  memset(&adr_srvr, 0, sizeof(adr_srvr));
  
  if (argc ==2)
 adr_srvr.sin_addr.s_addr = inet_addr(argv[1]);
  else
 adr_srvr.sin_addr.s_addr = inet_addr("192.168.1.20");
  

  adr_srvr.sin_family = AF_INET;
  adr_srvr.sin_port = htons(9090);
 
  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd == -1) {
 perror("socket error");
 exit(1);
  }

  z = connect(sockfd, (struct sockaddr *)&adr_srvr, sizeof(adr_srvr));
  if (z == -1) {
 perror("connect error");
 exit(1);
  }
  
  while (1) {
   z = read(sockfd, buf, 256);
   if (z == -1) {
  perror("read error");
  exit(1);
   }
   buf[z]=0;

 if (strncmp(buf, "stop", 4) == 0)
  break;
 
 printf("日期時間為: %s\n", buf); 
  }
  close(sockfd);
  return 0;
}

2015年10月5日 星期一

Socket網路程式設計(1):

    Linux OS使用Socket的觀念來設計網路程式,所以在介紹UDP,TCP網路程式設計前,先了解一下Socket的基本觀念。

    "Socket"有時又稱為[接口],是一種可做雙向資料傳輸的通道,可以將Socket想像成一種裝置,Linux程序可經由此裝置與本地端或是遠端的程序溝通。

    本次要介紹的UDP及TCP的網路程式主要是用到Internet-domain socket,如果我們能了解Internet-domain socket結構的定義相關函數的意義,就能寫出UDP及TCP的網路程式。

結構與相關函數:
        
        在設計網路程式之前,先說明Internet-domain socket的定址結構,此結構可以用來儲存IP位址、通訊口等訊息。
     

[sockaddr_in]定址結構:

    struct sockaddr_in{
             sa_family_t  sin_family;  /*AF_INET*/
             unsigned short int  sin_port;  /*port number*/
             struct in_addr  sin_addr;  /*Internet address*/
};

  sin_family:是用來說明socket所使用的定址模式,在此必須設為[AF_INET],表示是Internet-                          domain socket。
  sin_port:用來表示TCP/IP的port number,設定sin_port必須使用htons函數做位元排序的動作,                 會在之後說明。
  sin_addr:用來表示IP位址,結構如下。
                  struct in_addr{
                            unsigned long int s_addr;/*儲存IP位址*/
                   };

[inet_addr()函數]:

  inet_addr()函數可用來將[xxx.xxx.xxx.xxx]格式的IP位址轉換成ˇ32-bit unsigned integer。
  [格式]
             #include <sys/socket.h>
             #include <netinet/in.h>
             #include <arpa/inet.h> 
             unsigned long inet_addr(const char *string);
其中[string]為一個IP字串,他的格式為[XXX.XXX.XXX.XXX] 


位元排序函數:   

 在設定IPv4 Socket定址結構時,還有一點需要注意的是port number 的設置。
 假如我們要設定IP位址[192.168.1.10],port number為[8000],我們會做如下設定
  
  struct sockaddr_in adr_srvr;
  adr_srvr.sin_addr.s_addr = inet_addr("192.168.10");
  adr_srvr.sin_port = htons(8000);


  Socket():

  要完成TCP及UDP網路程式設計,需要呼叫許多的SOCKET函數,來幫助我們撰寫網路程式,不論是使用TCP及UDP作為傳輸協定,要透過SOCKET做資料傳輸,首要的工作就是建立SOCKET,要建立SOCKET就可使用socket()函數。

[Socket格式]

                       #include <sys/types.h>
                       #include <sys/socket.h>
                       int socket(int domain, int type, int protocol);

domain:網域,只要設定為[AF_INET]即可,表示使用Internet協定。

type:連結的型態,若設定值為[SOCK_STREAM]表示為TCP傳輸層協定,若設定值為                         [SOCK_DGRAM]表示為UDP傳輸層協定。

protocol:通訊協定,一般設為[0],表示自動選擇。


  Bind():

在通訊協定中我們可以使用Bind()函數將IPv4 socket定址結構,連結到我們所建立的socket,如此一來每當有封包到達網路介面時,Linux核心就會將這個封包導向所連結的socket。


[Bind格式]

                   #include<sys/socket.h>
                   int bind (int sockfd, const struct sockaddr *my_addr, size_t adr_len);

sockfd: socket函數執行後所傳回的socket描述子

my_addr:指向struct sockaddr_in結構的指標,用來存放欲連結的IPv4定址結構

adr_len: struct sockaddr_in結構的長度,可將其指定為sizeof(struct sockaddr_in)

Listen():

建立好socket並做好bind後,在server端,我們可以使用listen()函數來通知Linux核心,將socket設為[listening socket],等待client端的連線要求。

[Listen格式]

                    #include <sys/socket.h>
                    int listen(int sockfd, int backlog);

sockfd: socket函數執行後所傳回的socket描述子

backlog:指定最大連線數量,通常設為5

Accept():

當server端建立好listening socket並接收到client端的連線請求時,就會將連線請求放入連線佇列中,接著server端必須呼叫accept()函數,來處理並接受佇列中的連線請求。

[Accept格式]

                    #include <sys/socket.h>
                    int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen);

sockfd: socket函數執行後所傳回的socket描述子

addr:指向struct sockaddr_in結構的指標,用來存放client端的IP address

addrlen:存放client IP address變數的長度,初值應為sizeof(struct sockaddr_in),accept()執行成                 功後會存回實際的client IP address 長度


Connect():

在TCP中,當client端建立好了socket後可以呼叫connect()函數向server端要求建立連線,建立完畢後才能互傳資料。

[Connect格式]

                    #include <sys/socket.h>
                    int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

sockfd: socket函數執行後所傳回的socket描述子

serv_addr:指向struct sockaddr_in結構的指標,用來存放server端的IP address

addrlen: struct sockaddr_in結構的長度,可指定為sizeof(struct sockaddr_in)

Close():

我們可以呼叫close()函數來中止連線。

[Close格式]

                    #include <sys/socket.h>
                    int close(int sockfd);

sockfd: socket函數執行後所傳回的socket描述子

TCP程式設計流程:

在設計網路程式我們會分為客戶端與伺服端,綜合以上的說明,我們可以將Linux TCP程式設計流程,以下圖表示。





TCP輸出入函數:

當我們在server端建立了socket做好bind,產生listening socket,接受client端連線要求後,server端便可以與client端彼此傳遞資料,要傳遞資料,需要使用輸出入函數,TCP socket的輸出入函數有許多種,最基礎的便是read()、write()函數。

Read():

read()函數會從已開啟的socket讀取資料。

[Read格式]

                   #include <sys/socket.h>
                   int read(int sockfd, char *buf, int len);


sockfd: socket函數執行後所傳回的socket描述子

buf:指向字元暫存器的指標,用來儲存讀取到的資料

len:欲讀取的字元長度

Write():

write()函數可以將資料寫入已開啟的socket。

[Read格式]

                   #include <sys/socket.h>
                   int write(int sockfd, char *buf, int len);

sockfd: socket函數執行後所傳回的socket描述子

buf:指向字元暫存器的指標,用來儲存欲寫入的資料

len:欲寫入的字元長度

Recv():

recv()函數可以經由socket來接收資料。

[Recv格式]

                   #include <sys/types.h>
                   #include <sys/socket.h>
                   int recv(int s, void *buf, int len, unsigned int flags);
[note]:recv()用來接收遠端socket傳來的資料,並把資料儲存在buf指向的記憶體中,len為可接              收的最大長度,flags一般設為0

Send():

send()函數可以經由socket來傳送資料。

[Send格式]

                   #include <sys/types.h>
                   #include <sys/socket.h>
                   int send(int s, const void *msg, int len, unsigned int flags);
[note]:send()函數可以將msg指向的資料,經由socket傳送給遠端的主機,len則為傳送資料最大            長度,flags一般設為0。

--------------------------------------------------------------------------------------------------------------------------
由上述介紹後,我們來實作TCP通訊協定的server程式與client程式

動作要求:

1.server端會建立socket,連結socket,等待client端連線
2.client端會建立socket,與server連線,若成功,將str字串傳給server,str字串內容為[品號 品      名 售價]
3.server端若接受client端的連線,會讀取字串並解析內容,算出售價的含稅價,再將處理後的    字串回傳給client
4.client端收到server端的訊息,會將訊息顯示在螢幕上

程式:server端

/* server.c */

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>

int port = 8000;

int main(void)
{
  struct sockaddr_in sin;
  struct sockaddr_in pin;
  int mysock;
  int tempsock;
  int addrsize;
  char str[100],str1[20],str2[20],str3[20];
  char buf[100];
  int i, len1, len2;
  float c;

  mysock = socket(AF_INET, SOCK_STREAM, 0);
  if (mysock == -1) {
  perror("call to socket");
  exit(1);
  }

  bzero(&sin, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = htonl(INADDR_ANY);
  sin.sin_port = htons(port);

  if (bind(mysock, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
  perror("call to bind");
  exit(1);
  }

  if (listen(mysock, 20) == -1) {
  perror("call to listen");
  exit(1);
  }

  printf("Accepting connections ...\n");

  while(1) {
  tempsock = accept(mysock, (struct sockaddr *)&pin, &addrsize);
  if (tempsock == -1){
    perror("call to accept");
    exit(1);
  }

  len1=recv(tempsock, str, 100, 0);
  printf("\n收到字元數: %d\n",len1);
str[len1]=0;
printf("received from client: %s\n", str);

if (len1 > 0) {
strcpy(str1,strtok(str," "));
printf("第 1 個字串為: %s\n",str1);
strcpy(str2,strtok(NULL," "));
printf("第 2 個字串為: %s\n",str2);
strcpy(str3,strtok(NULL," "));
printf("第 3 個字串為: %s\n",str3);
c=atof(str3)*1.05;
sprintf(buf,"品號為 %s\n品名為 %s\n含稅價為: %.2f\n",str1, str2, c);
}
  len2 = strlen(buf);

  if (send(tempsock, buf, len2, 0) == -1) {
    perror("call to send");
    exit(1);
  }
  close(tempsock);
  }
  return 0;
}

程式:client端

/* client.c */

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

int port = 8000;

int main(int argc, char *argv[])
{
  struct sockaddr_in pin;
  int mysock;
  char buf[8192];
  char *str="A001 電視機 20000.00 ";

  if (argc < 2) {
printf("使用方法: client 字串\n");
printf("使用預設字串\n");
  } else {
str=argv[1];
  }
  
  bzero(&pin, sizeof(pin));
  pin.sin_family = AF_INET;
  pin.sin_addr.s_addr = inet_addr("192.168.1.20");
  pin.sin_port = htons(port);

  mysock = socket(AF_INET, SOCK_STREAM, 0);
  if (mysock == -1) {
  perror("call to socket");
  exit(1);
  }

  if (connect(mysock, (void *)&pin, sizeof(pin)) == -1) {
  perror("call to connect");
  exit(1);
  }

  printf("Sending message %s to server ...\n", str);

  if (send(mysock, str, strlen(str), 0) == -1) {
  perror("Error in send\n");
  exit(1);
  }


  if (recv(mysock, buf, 8192, 0) == -1) {
  perror("Error in receiving\n");
  exit(1);
  }

  printf("\nResponse from server: \n\n%s\n", buf);

  close(mysock);
  return 0;
}
--------------------------------------------------------------------------------------------------------------------------

 sin.sin_addr.s_addr = htonl(INADDR_ANY):

       讓Server端的socket可以接收同一個網域內所有的IP位址,INADDR_ANY可視為[萬用位            址],同樣地,若要讓socket接收同區網的所有port number,指令如下:
        sin.sin_port = htons(0);

指令列引數:

int main(int argc, char *argv[]){....}
此為C語言的一項功能,此功能可以讓程式在執行時,接受由使用者輸入一些字串,作為主程式的參數,其中第一個引數[argc]會儲存使用者輸入的字串個數,而第二個引數[argvp[]]為字串指標陣列,指向使用者所輸入的字串內容。
例如,當我們執行client程式可以輸入以下字串:
./client "A002 音響 15000.00"
此時,argc的值為2,argv[0]的內容為client,argv[1]的內容為"A002 音響 15000.00"。