2009年2月5日 星期四

socket - sctp

成功大學多媒體行動實驗室 有做出以下的產品耶 SCTP-MOVIDEO Server

要使用sctp必需先安裝sctp套件
$ sudo apt-get install libsctp-dev

在寫一個簡單的sctp的server-client出現以下錯誤
ren@notebook:~/svn/renyang-learn/socket/sctp/ftp/test$ gcc -c copy_clinet.c -o copy_clinet.o
In file included from copy_clinet.c:7:
/usr/include/netinet/in.h:84: 錯誤: expected identifier before numeric constant

找了很久,測了很久,才發現header file的擺放順序有問題!!?
若是下面順序的話,就會出現以上錯誤!
#include <sys/socket.h>
#include <netinet/sctp.h>
#include <netinet/in.h>

而以下就可以過
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>

這真是太神奇啦~

在編譯serv.c時會出現以下錯誤
ren@notebook:~/Desktop/homework$ gcc serv.c -o serv
/tmp/ccwbUY4s.o: In function `main':
serv.c:(.text+0x1eb): undefined reference to `sctp_sendmsg'
collect2: ld returned 1 exit status

解決方法:多加一個 -lsctp 的參數
ren@notebook:~/Desktop/homework$ gcc serv.c -lsctp -o serv

ren@notebook:~/svn/renyang-learn/socket/sctp/one-to-many$ make
gcc -Wall -O2 -c client.c -o client.o
client.c: In function 'main':
client.c:33: warning: implicit declaration of function 'inet_pton'
client.c:38: warning: implicit declaration of function 'close'

表示inet_pton與close函式的header file沒有正確的被include進來
分別要include arpa/inet.h和unistd.h

ren@notebook:~/svn/renyang-learn/socket/sctp/ftp$ make
gcc -c client.c -o client.o
In file included from client.c:4:
/usr/include/netinet/in.h:84: 錯誤: expected identifier before numeric constant
make: *** [client.o] Error 1

表示有重覆include in.h之類的

inet_pton函數:將點分十進位串轉換成網路位元組序二進位值,此函數對IPv4位址和IPv6位址都能處理。
#include <arpa/inet.h>
int inet_pton(int family,const char * strptr,void * addrptr);
返回:1---成功 0---輸入不是有效的表達格式 -1---失敗

strtol(將字符串轉換成長整型數)
表頭文件:#include <stdlib.h>
定義函數:long int strtol(const char *nptr,char **endptr,int base);
函數說明:strtol()會將參數nptr字符串根據參數base來轉換成長整型數。參數base範圍從2至36,或0。參數base代表採用的進制方式,如 base值為10則採用10進制,若base值為16則採用16進制等。當base值為0時則是採用10進制做轉換,但遇到如'0x'前置字符則會使用 16進制做轉換。一開始strtol()會掃描參數nptr字符串,跳過前面的空格字符,直到遇上數字或正負符號才開始做轉換,再遇到非數字或字符串結束時('\0')結束轉換,並將結果返回。若參數endptr不為NULL,則會將遇到不合條件而終止的nptr中的字符指針由endptr返回。
返回值:返回轉換後的長整型數,否則返回ERANGE並將錯誤代碼存入errno中。
附加說明:ERANGE指定的轉換字符串超出合法範圍。
參考網站

參考資料:
SCTP Programmer's Guide
Stream Control Transmission Protocol (SCTP)
IBM SCTP socket API
SCTP Programmer's Guide: HP
以IPv6有線/無線網路Multihome-based SCTP通訊協定實作之可切換式多媒體視訊串流平台
一些sctp的文章
我國IPv6建置發展計畫
The Stream Control Transmission Protocol(SCTP) Research and simulation Page
程式資料
Linux C編程---網路編程

SCTP相關網站:
傳輸層:TCP、UDP 和 SCTP
lksctp Project
Quick HOWTO : Ch15 : Linux FTP Server Setup
使用 SCTP 優化網路
Linux Kernel SCTP
Stream Control Transmission Protocol
Solaris(TM) Stream Control Transmission Protocol (SCTP)
Better networking with SCTP
SCTP Features

2009年2月4日 星期三

socket - tcp - 觀念

程式寫出來了,觀念還是要說一下,tcp實作檔案傳輸請到這裡

IPv4的定義:
struct in_addr {
  in_addr_t s_addr;
};
struct sockaddr_in{
  unit8_t sin_len;
  sa_family_t sin_family;
  in_port_t sin_port;
  struct in_addr sin_addr;
char sin_zero[8];
};

一般在使用socket通訊時,分身為server的應用程式必需先建立一個通訊端(socket)
再以bind系統呼叫(system call)來完成通訊端的命名
server的應用程式會以listen系統呼叫來建立一個佇列(queue)
再以accept系統呼叫來進行接收
建立好連線之後,通訊端可看做是一個低階的檔案描述子(file descriptor)程式,只要利用read及write指令即可完成雙向的資料通訊

Socket提供了兩種通訊型式
–AF_UNIX
•主要是用來讓單一台電腦內的兩個應用程式,利用標準(或非標準)裝置的埠(PORT)來做資料的傳輸

–AF_INET
•基本的Internet Protocol(IP)的通訊協定,其又可分為stream與datagram等兩層的服務
–Stream是一種可靠的雙向通訊方式,可確保資料的完整性
–Datagram是一種不需要建立連結的通訊方式,無法保證所傳送出資料的完整性

在Linux和Windows網絡編程時需要用到htons和htonl函數,用來將主機字節順序轉換為網絡字節順序。
得到的結果是4096,一開始看感覺很怪。

解釋如下,數字16的16進製表示為0x0010,數字4096的16進製表示為0x1000。由於Intel機器是little-end,存儲數字16時實際順序為1000,存儲4096時實際順序為0010。因此在發送網絡包時為了報文中數據為0010,需要經過htons進行字節轉換。如果用IBM等big-end機器,則沒有這種字節順序轉換,但為了程序的可移植性,也最好用這個函數。

另外用注意,數字所佔位數小於或等於一個byte(8 bits)時,不要用htons轉換。這是因為對於主機來說,big-end and little-end的最小單位為字節(byte)。

sin_family指代協議族,在socket編程中只能是AF_INET
sin_port存儲端口號(使用網絡字節順序)
sin_addr存儲IP地址,使用in_addr這個數據結構
sin_zero是為了讓sockaddr與sockaddr_in兩個數據結構保持大小相同而保留的空字節。
s_addr按照網絡字節順序存儲IP地址
sockaddr_in和sockaddr是並列的結構,指向sockaddr_in的結構體的指針也可以指向
sockadd的結構體,並代替它。也就是說,你可以使用sockaddr_in建立你所需要的信息,
在最後用進行類型轉換就可以了bzero((char*)&mysock,sizeof(mysock));//初始化
mysock結構體名
mysock.sa_family=AF_INET;
mysock.sin_addr.s_addr=inet_addr("192.168.0.1");
……
等到要做轉換的時候用:
(struct sockaddr*)mysock
換句話說在設定的時候用sockaddr_in
而在使用的時候用sockaddr
其實sockaddr_in與sockaddr是一樣的東西
我想是因為要相容於之後的版本,所以,在設定的時候用不同的sockaddr_in
而真正在使用的時候,均使用sockaddr,也就是要轉換成sockaddr的指標

詳細資料可以參考我寫的tcp程式碼,我有註釋在裡面!

[2009.04.30 補充]
在同一個ip,應用程式不可以bind同一個port,但是,透過
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &flag, len);
可以決解目前這一個問題,詳情請看
socket編程:SO_REUSEADDR例解 (轉)

參考資料:
結構體sockaddr_in和sockaddr用法的問題
TCP 與 UDP
複製檔案 - fread fwrite
請問int a=send(socket,buf,len,flags) 這個a是代表發送的包的大小嗎?(各個參數值已知的情況下)

return與exit的區別

exit是結束一個程序,它將刪除程序使用的記憶體空間,同時把錯誤訊息回傳給父程序,在父程序中wait系統呼叫將接受到此返回訊息。

例子:
void a()
{
  exit();
}
void main()
{
  while(1)
  {
    a();
  }
}

這個程序並不會死循環,因為在a函數中調用exit,所以整個程序就結束了。但如果你在a函數中使用return,那麼就是個死循環了。

例子2:
#include <iostream.h>
using namespace std;
class bbb
{
    public:
        bbb();
        ~bbb();
};

bbb::bbb()
{
    // do nothing
}

bbb::~bbb()
{
    cout << "destruct" << endl;;
}

main()
{
    bbb b;
    //exit(0);
    return 0;
}

然後把//exit(0)的註釋去掉再編譯運行一次。會有不同的結果。

答:當沒有exit(0)時,return 0時,系統會輸出並清理緩衝區並關閉標準輸入cin、標準輸出cout、標準錯誤cerr、標準日誌clog。

當有exit(0)時,c函數會輸出並清理stdin, stdout,現在stdout已經被關閉了,在執行return 0時,cout的緩衝區的數據已經沒有寫入的目標了,所以無輸出。

這只能說明cout和stdout, cin 和stdin用的是不同的緩衝區。

參考資料:
return與exit的區別是什麼?
return和exit的區別

解決ubuntu的解析度

這次回家,
在家裡那一台爛電腦灌ubuntu 8.04,
一開始沒有問題,但是,更新完驅動程式,哭哭~看不到螢幕~
因為螢幕太爛,
找了一堆解決方式,最後,有解決~

不過,我忘記用哪一個方法解決了,下次再回家查好了~


參考資料:
ubuntu 螢幕解析度及 flash 問題解決
ubuntu - 寬螢幕解析度設定
解決ubuntu登入畫面解析度錯誤

2009年2月3日 星期二

I/O - STDIN_FILENO

STDIN_FILENO 是标准输入的文件描述符
详见/usr/include/unistd.h
代码:
/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */

例:
int read(STDIN_FILENO, char *buffer, int sizeof(buffer));

例:
stdin
是讓使用者輸入字串,且回傳的是FILE的指標



參考資料:
STDIN和STDIN_FILENO的區別
file and stream : stdin and STDIN_FILENO
read function 設定Non-Blocking I/O的方式

socket - udp

以下有一個簡單的透過UDP來傳送訊息的程式,udp與tcp的差別在於tcp不能由server連續傳訊息給client而必需client-server-client間接傳。
而udp就可以由server連續傳訊息給client
udpserver.c

//==============================include file==========================
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
//====================================================================

//==============================define variable=======================
#define MAXLINE 80
#define SERV_PORT 8888
//====================================================================

//==============================define function=======================
void do_echo(int sockfd,struct sockaddr *pcliaddr,socklen_t clilen);
//====================================================================

//=============================main function==========================
int main(int argc,char *argv[])
{
  int sockfd;
  struct sockaddr_in servaddr,cliaddr;

  // create a socket, using the UDP
  sockfd = socket(AF_INET,SOCK_DGRAM,0);

  // init servaddr
  memset(&servaddr,0,sizeof(servaddr));
  servaddr.sin_family=AF_INET;
  servaddr.sin_addr.s_addr=INADDR_ANY;
  servaddr.sin_port=htons(SERV_PORT);

  // bind address and port to socket
  if (bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1)
  {
    perror("bind error,the ip address is wrong");
    exit(1);
  }

  do_echo(sockfd,(struct sockaddr*)&cliaddr,sizeof(cliaddr));

  return 0;
}
//====================================================================

//==============================function implement====================
void do_echo(int sockfd,struct sockaddr *pcliaddr,socklen_t clilen)
{
  int n;
  socklen_t len;
  char mesg[MAXLINE];

  for (;;)
  {
    len=clilen;
    // wait for receive data
    n = recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&len);
    // sent data back to client
    sendto(sockfd,mesg,n,0,pcliaddr,len);
  }
}
//====================================================================


udpclient.c

//=============================include file================================
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
//=========================================================================

//=============================define variable=============================
#define MAXLINE 80
#define SERV_PORT 8888
//=========================================================================

//=============================define function=============================
void do_cli(FILE *fp,int sockfd,struct sockaddr *pservaddr,socklen_t servlen);
//=========================================================================

//=============================main function===============================
int main(int argc,char *argv[])
{
  int sockfd;
  struct sockaddr_in servaddr;
  char error_message[20];

  // check args
  if (argc!=2)
  {
    printf("usage:udpclient <IP address>\n");
    exit(1);
  }

  // init servaddr
  memset(&servaddr,0,sizeof(servaddr));
  servaddr.sin_family=AF_INET;
  servaddr.sin_port=htons(SERV_PORT);
  if(inet_pton(AF_INET,argv[1],&servaddr.sin_addr)<=0)
  {
    sprintf(error_message,"[%s] is not a valid IP address\n",argv[1]);
    fputs(error_message,stderr);
    exit(1);
  }

  // build the socket, using the UDP
  sockfd=socket(AF_INET,SOCK_DGRAM,0);

  do_cli(stdin,sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));

  return 0;
}
//=========================================================================


//=============================function implement==========================
void do_cli(FILE *fp,int sockfd,struct sockaddr *pservaddr,socklen_t servlen)
{
  int n;
  char sendline[MAXLINE],recvline[MAXLINE+1];

  // connect to server
  if (connect(sockfd,pservaddr,servlen)==-1)
  {
    perror("connect error");
    exit(1);
  }

  while (fgets(sendline,MAXLINE,fp)!=NULL)
  {
    // read a line and send to server
    write(sockfd,sendline,strlen(sendline));
    // receive data from server
    n=read(sockfd,recvline,MAXLINE);
    if (n==-1)
    {
      perror("read error");
      exit(1);
    }
    // terminate string
    // 依字串的最後面加上一個結束符號
    recvline[n]=0;
    fputs(recvline,stdout);
  }
}
//=========================================================================


有用到的新的東西:
void * memset ( void * ptr, int value, size_t num );
把ptr指標指到的地方,用value的值填滿num個
參考

host to network short
uint16_t htons(uint16_t hostshort);
htons函數用來轉換u_short了來自主機的TCP / IP網絡字節順序(即big-endian )的.
參數hostshort [ ] 16位元數的主機字節順序.
返回值的htons函數返回值的TCP / IP網路字元順序.
須知htons函數有一個16位號碼主機字元順序並返回一個16位數字網路字元
參考
參考2
參考3
htons-htons的功能

FILE * stdin
等待使用者輸入字串,並回傳FILE的指標,與scanf比起來,scanf會以「空白」當作分隔
但是,透過char * fgets ( char * str, int num, stdin );
會把使用者輸入的字串存放到str的指標中,且長度必需小於num-1,如此一來不會以「空白」當作中斷
當我們輸入"good"時,實際上存到str的會是"good\n",也就是在最後面加上一個結束符號。
這裡要注意的是它自動加入的是null
A null character is automatically appended in str after the characters read to signal the end of the C string.
但是非常奇怪的就是用strlen(str)會比原來的長度還要加1,所以,我猜測最後加入的不是'\0'而是'\n',所以,長度才會比原本的多一
這裡就要提到,若使用char *gets( char *str )
不會在最後加入一個結束符號。

FILE *stdout
可以把字串傳送到螢幕上
透過int fputs ( const char * str, stdout);
可以把str指標指到的字串送到螢幕上

FILE *stderr
可以把字串送到錯誤串流
透過int fputs(const char *str,stderr);
可以把str指標指到的字串送到螢幕上

void perror ( const char * str );
perror()用來將上一個函數發生錯誤的原因輸出到標準錯誤(stderr)。參數s所指的字串會先印出,後面再加上錯誤原因字串。此錯誤原因依照全局變量errno的值來決定要輸出的字符串。
若上一個函數沒有執行失敗的話,那就會出現
"訊息":SUCCESS
參考
參考2
參考3
參考4
參考5

上面的一些函數後面都不能加變數,因此可能必需與
int sprintf ( char * str, const char * format, ... );
一起使用。先把所有的變數一起轉成字串,再把字串傳給上面幾個函數使用
參考

int fprintf ( FILE * stream, const char * format, ... );
把字串輸入到檔案中
fprintf(stderr,"there are some errors:%s",string);
回傳值是寫入多少字元

參考資料:
recvfrom
練習 Socket UDP 通訊實驗
socket編程原理
STDIN
編寫Linux下的UDP Client/Server程序

socket - tcp

當client與server連接之後,
client可以連續傳訊息給server,
但是,server不能連續傳訊息給client,
像是server要傳檔案給client,分割好幾份,
則在server傳給client每一份之間,client必需傳一個訊息給server,
如此一來,server才可以傳下一份分割給client
下面我用gcc寫了一個非常簡單的傳輸檔案的程式:
server.c

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

//==========================define variable===============================
#define PORT 9734
#define FILEBUFFERSIZE 1024
//========================================================================

//==========================global variable===============================
//========================================================================

//==========================function phototypes===========================
//========================================================================

int main(int argc,char *argv[])
{
  int listenfd,connfd;
  // 在c語言中,要用到struct時,前面必需要加上struct,在c++中則不需要
  struct sockaddr_in server_address;
  struct sockaddr_in client_address;
  int server_len,client_len;
  char temp[FILEBUFFERSIZE];
  int ReadByte,WriteByte;
  char end[]="#end#"; // 用來判斷是否傳送檔案結束
  FILE *fp;

  if (argc!=2) {
    printf("Insrtuction error!!\n");
    printf("./server 'file'\n");
    exit(1);
  }
  if ((fp=fopen(argv[1],"rb"))==NULL) {
    fputs("open file error\n",stderr);
    exit(1);
  }
  // divide - test
  while((ReadByte=fread(temp,sizeof(char),FILEBUFFERSIZE,fp))>0) {
    printf("%d\n",ReadByte);
    memset(temp,0,FILEBUFFERSIZE);
  }
  // divide - test

  // 1.建立一個新的通訊端:socket(int domain,int type,int protocol),並回傳參數值
  listenfd = socket(AF_INET, SOCK_STREAM, 0);
  // 2.1.設定為Unix network socket,表示可以在兩個不同的電腦之間傳資料
  server_address.sin_family = AF_INET;
  // 2.2.server的ip位址,這裡必需是server的ip位
  // inet_addr(), this function translate IP address into specified format for socket
  server_address.sin_addr.s_addr=INADDR_ANY;
  // server_address.sin_port = 9734;
  // 2.3.轉換成little-end,因為intel是little-end
  server_address.sin_port = htons(PORT);
  // 記錄server端的設定(port,ip,sin_family...)的資料長度
  server_len = sizeof(server_address);
  // 3.Socket 出入口需Binding到TCP address
  if(bind(listenfd,(struct sockaddr*) &server_address, server_len)==-1){
    printf("bind error");
    exit(1);
  }
  // 4.建立一個queue以接收其他程式所送達的連線要求,queue的大小為5
  if (listen(listenfd,5)==-1){
    printf("listening error");
    exit(1);
  }
  // 當產生了一個佇列(queue)後,再來就是要把queue中的連結請求(Connect Request)讀出
  while(1)
  {
    // temp存放要傳送的檔案
    char temp[FILEBUFFERSIZE];
    printf("server waiting \n");
    client_len = sizeof(client_address); // 了解client的設定資料結構長度
    // 5.以accept指令來等待client端送去連線要求(connect request)
    // 由client_address獲得client端的網路位置
    // connfd即由新的connected socket 所存放參數的地方。用來和client 進行資料輸出入
    connfd = accept(listenfd,(struct sockaddr *)&client_address, &client_len);
    if (connfd==-1){
      printf("Error:accept()\n");
      exit(1);
    }
    // 由connfd讀取資料存到temp的位址中,buffer大小為1024 bytes
    read(connfd, &temp, FILEBUFFERSIZE);
    if (printf("ch : %s \n",temp)==-1){
      printf("Read error!\n");
      exit(1);
    }
    else
    {
      if (strncmp(temp,"get",strlen("get"))==0)
      {
        printf("File transmite...\n");
        fp=fopen(argv[1],"rb");
        if (fp==NULL) {
          printf("open file error!!\n");
          exit(1);
        }
        memset(temp,0,sizeof(temp));
        ReadByte=fread(temp,sizeof(char),FILEBUFFERSIZE,fp);
        while(ReadByte>0){
          printf("read %d Byte\n",ReadByte);
          WriteByte=write(connfd,temp,ReadByte);
          printf("transmite %d bytes\n",WriteByte);
          memset(temp,0,sizeof(temp));
          ReadByte=read(connfd,temp,FILEBUFFERSIZE);
          printf("%s\n",temp);
          memset(temp,0,FILEBUFFERSIZE);
          ReadByte=fread(temp,sizeof(char),FILEBUFFERSIZE,fp);
        }

      }
      WriteByte=write(connfd,end,sizeof(end));
      printf("Transmite %d bytes\n",WriteByte);
    }
    // 關掉connected socket
    close(connfd);
  }
  // 關掉listen的socket
  close(listenfd);
  fclose(fp);

  return 0;
}

//==========================function implementation=======================
//========================================================================


client.c

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

//=============================define variable===============================
#define PORT 9734
#define FILEBUFFERSIZE 1024
//===========================================================================

int main(int argc,char *argv[])
{
  int sockfd;
  int ReadByte;
  struct sockaddr_in address;
  int client_len,result;
  FILE *fp;
  char server_addr[15];
  if (argc!=2) {
    fputs("./client get",stderr);
    exit(1);
  }
  if((fp=fopen("copy","wb"))==NULL) {
    printf("create error\n");
    exit(1);
  }
  fclose(fp);
  printf("Please input server's ip:");
  scanf("%s",server_addr);
  // 建立一個socket
  sockfd = socket(AF_INET, SOCK_STREAM, 0);   address.sin_family = AF_INET;
  // 以下存放的必需是server的ip位址
  address.sin_addr.s_addr=inet_addr(server_addr);
  address.sin_port = htons(PORT);
  client_len = sizeof(address);
  // Client端則呼叫connect()功能,要求與Server主機建立連接通道
  result = connect(sockfd, (struct sockaddr *)&address,client_len);
  if(result == -1)  // 若傳回-1則表示連線失敗
  {
    perror("oops: client1");
    fclose(fp);
    exit(1) ;
  }
  // 傳送資料到server端
  if (write( sockfd, &(*argv[1]) , FILEBUFFERSIZE)==-1){
    printf("write error\n");
    fclose(fp);
    exit(1);
  }
  else {
    // 接收檔案
    char temp[FILEBUFFERSIZE];
    memset(temp,0,FILEBUFFERSIZE);
    ReadByte=read(sockfd,temp,FILEBUFFERSIZE);
    printf("get the %d bytes\n",ReadByte);
    fp = fopen("copy","wb");
    if (fp==NULL) {
      printf("open file error!!\n");
      exit(1);
    }
    else {
      while(ReadByte>0) {
        if (strncmp(temp,"#end#",strlen("#end#"))==0) {
          printf("The connect is over\n");
          break;
        }
        fwrite(temp,sizeof(char),ReadByte,fp);
        write(sockfd,"I got\n",sizeof("I got\n"));
        memset(temp,0,FILEBUFFERSIZE);
        ReadByte=read(sockfd,temp,FILEBUFFERSIZE);
        printf("I got the %d bytes\n",ReadByte);
      }
      fclose(fp);
    }
    // 當client接收到資料後,必需要write資料到server才能再read資料!,這樣才叫被動啊!!
  }
  close( sockfd); // 關掉socket介面

  return 0;
}

執行:

[user@host ~]$ ./server source
[user@host ~]$ ./client get

就會在目錄下出現一個copy的檔案

這裡用到的新函數
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
由FILE指標指到的檔案讀取單位為size byte,且個數上限為count的資料,並存到ptr所指到的指標位址空間,回傳值為實際讀取到的byte數

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
由FILE指標指到的檔案寫入單位為size byte,且個數上限為count的資料,並存到ptr所指到的指標位址空間,回傳值為實際寫入到的byte數

int socket(int domain, int type, int protocol)
– Doman : AF_UNIX UNIX files system sockets
AF_INET → UNIX network sockets
AF_ISO → ISO standard protocols
AF_NS → Xerox Network Systems protocols
AF_IPX → Novell IPX protocol
– Type : SOCK_STREAM(TCP),SOCK_DGRAM(UDP)
– Protocol : default 0

int bind(int socket, const struct socket * address, size_t address_len);
socket : return value from socket function
– 利用socket函數產生socket後所回傳的參數值
• *address : struct sockaddr_un, struct sockaddr_in
– 對映於通訊端(socket)所宣告的資料結構
• address_len : address length
– 參數為資料結構的大小
當成功後,函式會傳回0以代表成功,若失敗即傳回-1。

建立一個queue以接收其他程式所送達的連線要求(request)
– int listen(int socket, int backlog)
• socket : return value from socket function
– 為所新建立的socket descriptor
• Backlog : Queue length
– 代表所欲建立的queue大小為多少
當成功後,函式會傳回0以代表成功,若失敗即傳回-1。

當產生了一個佇列(queue)後,再來就是要把queue中的連結請求(Connect Request)讀出
• 其函數的原型如下:
– int connect(int socket, const struct sockaddr
*address, size_t address_len)
• socket : return value from socket function
– 為新建立的socket descriptor
• *address : struct sockaddr_un, struct sockaddr_in
– 對映於通訊端(socket)所宣告的資料結構
• address_len : address length
– 為address資料結構的大小

SOCKET accept(SOCKET s,struct sockaddr* addr,int* addrlen);
s:一個設定為listen狀態的socket
sddr:Client端位址資訊,由函式自動產生填入
addrlen:sddr長度,由函式自動產生
回傳值:-1表示錯誤,否則傳回另一個包含Client端資訊的新socket
descriptor,作為傳送資料用
傳進accept()的listen socket本身並沒有辦法作資料的傳輸,所以必須透過accept()產生一個包含通訊協定、Server、Client資訊的新socket,利用他就可以進行資料的傳輸了

int count=send( int sockfd, char *buffer, int buflen, int flags )

–count:傳送資料的大小
–buffer:資料傳送的指標
–buflen:資料長度
–flag:通常設為0
–return為實際傳送的byte數
–Or write
• int write(int sockfd, char * buffer, int buflen);

Int count=recv( int sockfd, char *buffer, int buflen, int flags )
–Count:接收到的資料大小
–buffer:資料接收後儲存位址的指標
–buflen:資料長度
–flag:通常設為0
–return為實際傳送的byte數
–Or read
• int read(int sockfd, char * buffer, int buflen);

int close (int sockfd) ;
用來關閉socket,並且終止TCP連線


參考資料:
Linux socket 編程入門
網路程式規畫
TCP通訊協定的server程式及client程式
socket編程原理
使用Socket完成FTP檔案存取
程式設計範例及習題 Chapter 5 網路程式範例
Socket Programming HOWTO

以後可能會用到:
[C/C++] 解決Socket連續Bind同一個Port的問題
UNIX Network Programming Source Code