Berkeley套接字

TCP 基本流程圖
互聯網伯克利套接字，又稱為BSD 套接字（Internet Berkeley sockets，BSD sockets） ，是一種應用程序接口（API），用於網絡套接字（ socket）與Unix域套接字，包括了一個用C語言寫成的應用程序開發庫，主要用於實現進程間通訊，在計算機網絡通訊方面被廣泛使用。
Berkeley套接字（也作BSD套接字應用程序接口）剛開始是4.2BSD Unix操作系統（於1983發佈）的一套應用程序接口。然而，由於AT&T的專利保護著UNIX，所以只有在1989年伯克利大學才能自由地發佈自己的操作系統和網絡庫。
Berkeley套接字應用程序接口形成了事實上的網絡套接字的標準精髓。 大多數其他的編程語言使用與這套用C語言寫成的應用程序接口 類似的接口。 這套應用程序接口也被用於Unix域套接字（Unix domain sockets），後者可以在單機上為進程間通訊（IPC）的接口。
這種基於流的傳輸層接口（TLI）為套接字應用程序接口提供了一種選擇。 

**Berkeley套接字接口**
Berkeley套接字接口，一個應用程序接口（API），使用一個Internet套接字的概念，使主機間或者一臺計算機上的進程間可以通訊。 它可以在很多不同的輸入/輸出設備和驅動之上運行，儘管這有賴於操作系統的具體實現。 接口實現用於TCP/IP協議，因此它是維持Internet的基本技術之一。 它是由加利福尼亞的伯克利大學開發，最初用於Unix系統。 如今，所有的現代操作系統都有一些源於Berkeley套接字接口的實現，它已成為連接Internet的標準接口。
套接字接口的接入有三個不同的級別，最基礎的也是最有效的就是raw socket級別接入。 很少的應用程序需要在外向通訊控制的這個級別接入，所以raw socket級別是隻為了用於開發計算機Internet相關技術的。 最近幾年，大多數的操作系統已經實現了對它的全方位支持，包括Windows XP。

**使用Berkeley套接字的系統**
由於Berkeley套接字是第一個socket，大多數程序員很熟悉它們，所以大量系統把伯克利套接字作為其主要的網絡API。一個不完整的列表如下：- Windows Sockets (Winsock) ，和Berkeley Sockets很相似，最初是為了便於移植Unix程序。- Java Sockets - Python sockets- Perl sockets

**頭文件**
Berkeley套接字接口的定義在幾個頭文件中。這些文件的名字和內容與具體的實現之間有些許的不同。 大體上包括：
; 
: 核心BSD套接字核心函數和數據結構。
: AF_INET、AF_INET6 地址集和它們相應的協議集PF_INET、PF_INET6. 廣泛用於Internet，這些包括了IP地址和TCP、UDP端口號。
; 
: AF_INET 和AF_INET6 地址家族和他們對應的協議家族 PF_INET 和 PF_INET6。在互聯網編程中廣泛使用，包括IP地址以及TCP和UDP端口號。
; 
: PF_UNIX/PF_LOCAL 地址集。用於運行在一臺計算機上的程序間的本地通信，不用於網絡通訊。
; 
: 處理數值型IP地址的函數。
; 
: 將協議名和主機名翻譯為數值地址的函數。搜索本地數據以及DNS。

**套接字API函數**
這個列表是一個Berkeley套接字API庫提供的函數或者方法的概要：- socket() 創建一個新的確定類型的套接字，類型用一個整型數值標識（文件描述符），併為它分配系統資源。- bind() 一般用於服務器端，將一個套接字與一個套接字地址結構相關聯，比如，一個指定的本地端口和IP地址。- listen() 用於服務器端，使一個綁定的TCP套接字的tcp狀態由CLOSE轉至LISTEN；操作系統內核為此監聽socket所對應的tcp服務器建立一個pending socket隊列和一個established socket隊列；參數backlog指定pending socket隊列的長度，0表示長度可以無限大。pending socket，就是某客戶端三次握手的syn包到達，內核為這個syn包對應的tcp請求生成一個socket（狀態為SYN_RECV），但三次握手還沒有完成時的socket。- connect() 用於客戶端，為一個套接字分配一個自由的本地端口號。 如果是TCP套接字的話，它會試圖獲得一個新的TCP連接。- accept() 用於服務器端。 它接受一個從遠端客戶端發出的創建一個新的TCP連接的接入請求，創建一個新的套接字，與該連接相應的套接字地址相關聯。- send()和recv(),或者write()和read(),或者recvfrom()和sendto(), 用於往/從遠程套接字發送和接受數據。- close() 用於系統釋放分配給一個套接字的資源。 如果是TCP，連接會被中斷。- gethostbyname()和gethostbyaddr() 用於解析主機名和地址。- select() 用於修整有如下情況的套接字列表： 準備讀，準備寫或者是有錯誤。- poll() 用於檢查套接字的狀態。 套接字可以被測試，看是否可以寫入、讀取或是有錯誤。- getsockopt() 用於查詢指定的套接字一個特定的套接字選項的當前值。- setsockopt() 用於為指定的套接字設定一個特定的套接字選項。
更多的細節如下給出。

**socket()**
socket() 為通訊創建一個端點，為套接字返回一個文件描述符。 socket() 有三個參數：- domain 為創建的套接字指定協議集（或稱做地址族 address family)。 例如：
** AF_INET 表示IPv4網絡協議
** AF_INET6 表示IPv6
** AF_UNIX 表示本地套接字（使用一個文件）- type（socket類型）如下：
** SOCK_STREAM （可靠的面向流服務或流套接字）
** SOCK_DGRAM （數據報文服務或者數據報文套接字）
** SOCK_SEQPACKET （可靠的連續數據包服務）
** SOCK_RAW (在網絡層之上自行指定運輸層協議頭，即原始套接字)- protocol 指定實際使用的傳輸協議。 最常見的就是IPPROTO_TCP、IPPROTO_SCTP、IPPROTO_UDP、IPPROTO_DCCP。這些協議都在中有詳細說明。 如果該項為“0”的話，即根據選定的domain和type選擇使用缺省協議。
如果發生錯誤，函數返回值為-1。 否則，函數會返回一個代表新分配的描述符的整數。
原型：
int socket(int domain, int type, int protocol);

**bind()**
bind() 為一個套接字分配地址。當使用socket()創建套接字後，只賦予其所使用的協議，並未分配地址。在接受其它主機的連接前，必須先調用bind()為套接字分配一個地址。bind()有三個參數：- sockfd, 表示使用bind函數的套接字描述符- my_addr, 指向sockaddr結構（用於表示所分配地址）的指針- addrlen, 用socklen_t字段指定了sockaddr結構的長度
如果發生錯誤，函數返回值為-1，否則為0。
原型:
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);

**listen()**
當socket和一個地址綁定之後，listen()函數會開始監聽可能的連接請求。然而，這隻能在有可靠數據流保證的時候使用，例如：數據類型(SOCK_STREAM, SOCK_SEQPACKET)。
listen()函數需要兩個參數：- sockfd, 一個socket的描述符.- backlog, 完成三次握手、等待accept的全連接的隊列的最大長度上限。對於AF_INET類型的socket，全連接數量為：min(backlog, somaxconn)。當隊列滿時，新的全連接會返回錯誤。somaxconn默認為128.半連接隊列的最大長度可通過sysctl函數設置tcp_max_syn_backlog，默認值為256。Linux Kernel 2.2之後，全連接隊列與半連接隊列分別叫做accept queue與syns queue。根據/proc/sys/net/ipv4/tcp_abort_on_overflow裡的值為0表示如果三次握手第三步的時候全連接隊列滿了，那麼server扔掉client發過來的ack，server過一段時間再次發送syn+ack給client（也就是重新走握手的第二步），如果client超時等待比較短，就很容易異常；tcp_abort_on_overflow為1表示第三次握手時如果全連接隊列滿了，server發送一個reset包給client，表示廢掉這個握手過程和這個連接。
一旦連接被接受，返回0表示成功，錯誤返回-1。
原型:
int listen(int sockfd, int backlog);

**accept()**
當應用程序監聽來自其他主機的面對數據流的連接時，通過事件（比如Unix select()系統調用）通知它。必須用 accept()函數初始化連接。 accept()為每個連接創立新的套接字並從監聽隊列中移除這個連接。它使用如下參數：- sockfd,監聽的套接字描述符- cliaddr, 指向sockaddr 結構體的指針，客戶機地址信息。- addrlen,指向 socklen_t的指針，確定客戶機地址結構體的大小 。
返回新的套接字描述符，出錯返回-1。進一步的通信必須通過這個套接字。
Datagram 套接字不要求用accept()處理，因為接收方可能用監聽套接字立即處理這個請求。
函數原型：
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

**connect()**
connect()系統調用為一個套接字設置連接，參數有文件描述符和主機地址。 
某些類型的套接字是無連接的，大多數是UDP協議。對於這些套接字，連接時這樣的：默認發送和接收數據的主機由給定的地址確定，可以使用 send()和 recv()。
返回-1表示出錯，0表示成功。
函數原型：
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);

**select()**
int select (int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout);- 第一個參數nfds：沒有用，僅僅為與伯克利Socket兼容而提供。 - 第二個參數readfds：指定一個Socket數組，select檢查該數組中的所有Socket。如果成功返回，則readfds中存放的是符合‘可讀性’條件的數組成員（如緩衝區中有可讀的數據）。- 第三個參數writefds：指定一個Socket數組，select檢查該數組中的所有Socket。如果成功返回，則writefds中存放的是符合‘可寫性’條件的數組成員（包括連接成功）。- 第四個參數exceptfds：指定一個Socket數組，select檢查該數組中的所有Socket。如果成功返回，則cxceptfds中存放的是符合‘有異常’條件的數組成員（包括連接接失敗）。- 第五個參數timeout：指定select執行的最長時間，如果在timeout限定的時間內，readfds、writefds、exceptfds中指定的Socket沒有一個符合要求，就返回0。

**getsockname() 和 getpeername ()**
int getsockname (SOCKET s, struct sockaddr *name, int* namelen);
getsockname函數獲取已綁定（可能是未調用bind的系統自動綁定）的套接口本地協議地址。
int getpeername (SOCKET s, struct sockaddr *name, int* namelen);
getpeername函數獲得與指定套接口連接的遠程信息（IP:PORT）。

**gethostbyname() 和 gethostbyaddr()**
gethostbyname() 和 gethostbyaddr()函數是用來解析主機名和地址的。可能會使用DNS服務或者本地主機上的其他解析機制（例如查詢/etc/hosts）。返回一個指向 struct hostent的指針，這個結構體描述一個IP主機。函數使用如下參數： - name 指定主機名。例如 www.wikipedia.org- addr 指向 struct in_addr的指針，包含主機的地址。- len 給出 addr的長度，以字節為單位。- type 指定地址族類型 （比如 AF_INET）。
出錯返回NULL指針，可以通過檢查 h_errno 來確定是臨時錯誤還是未知主機。正確則返回一個有效的 struct hostent *。
這些函數並不是伯克利套接字嚴格的組成部分。這些函數可能是過時了，只能處理IPv4地址。在IPv6中，替代的新函數是 getaddrinfo() and getnameinfo(), 這些新函數是基於addrinfo數據結構。參考。
函數原型：
struct hostent *gethostbyname(const char *name);
struct hostent *gethostbyaddr(const void *addr, int len, int type);

**setsockopt()**
int setsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
setsockopt函數用來設置套接字選項。
參數： -  sockfd:     套接字-  level:      協議層  SOL_SOCKET/IPPROTO_IP/IPPRO_TCP-  optname:    選項名  每一個協議層都有其固定的選項名-  optval:     緩衝區  set是指向將要存放的地址, get是指向目前存放信息的地址-  optlen:     緩衝區大小長度

在socket層, 有以下一些選項:- SO_BROADCAST         允許發送廣播數據                            int-  SO_DEBUG　　　　　　　　允許調試　　　　　　　　　　　　　　　　int-  SO_DONTROUTE　　　　　　不查找路由　　　　　　　　　　　　　　　int-  SO_ERROR　　　　　　　　獲得套接字錯誤　　　　　　　　　　　　　int-  SO_KEEPALIVE　　　　　　保持連接　　　　　　　　　　　　　　　　int-  SO_LINGER　　　　　　　 延遲關閉連接　　　　　　　　　　　　　　struct linger-  SO_OOBINLINE　　　　　　帶外數據放入正常數據流　　　　　　　　　int-  SO_RCVBUF　　　　　　　 接收緩衝區大小　　　　　　　　　　　　　int-  SO_SNDBUF　　　　　　　 發送緩衝區大小　　　　　　　　　　　　　int-  SO_RCVLOWAT　　　　　　 接收緩衝區下限　　　　　　　　　　　　　int-  SO_SNDLOWAT　　　　　　 發送緩衝區下限　　　　　　　　　　　　　int-  SO_RCVTIMEO　　　　　　 接收超時　　　　　　　　　　　　　　　　struct timeval-  SO_SNDTIMEO　　　　　　 發送超時　　　　　　　　　　　　　　　　struct timeval-  SO_REUSERADDR　　　　　 允許重用本地地址和端口　　　　　　　　　int-  SO_TYPE　　　　　　　　 獲得套接字類型　　　　　　　　　　　　　int-  SO_BSDCOMPAT　　　　　　與BSD系統兼容　　　　　　　　　　　　　 int

**ioctlsocket**
int ioctlsocket(_In_ SOCKET s,  _In_ long   cmd,   _Inout_ u_long *argp);
根據第二個參數的取值，設置socket I/O模式：
*FIONBIO：允許設置socket為阻塞或非阻塞：當第三個參數argp為0是阻塞模式，為非0則為非阻塞模式。如果已對一個套接口進行了WSAAsynSelect() 操作，則任何用ioctlsocket()來把套接口重新設置成阻塞模式的試圖將以WSAEINVAL失敗。為了把套接口重新設置成阻塞模式，應用程序必須首先用WSAAsynSelect()調用（IEvent參數置為0）來禁至WSAAsynSelect(), 或者通過設置lNetworkEvents參數為0來調用WSAEventSelect。
*FIONREAD：返回套接字s下一次自動讀入的數據量的大小。用來確定（determin）懸掛（pending）在網絡輸入緩衝區中，能從socket s中讀取的數據總數。返回單次recv函數能讀取的數據的總數 
*SIOCATMARK：返回所有的“緊急”（帶外）數據是否都已被讀入。僅適用於SOCK_STREAM類型的套接口，且該套接口已被設置為可以在線接收帶外數據（SO_OOBINLINE）

**inet_pton與inet_ntop**
inet_pton與inet_ntop兩個函數，在ASCII字符描述的IP地址與網絡字節序的4字節IP地址之間轉換。 字母"n"與"p"，分別是numerical與presentation的縮寫。

**協議和地址**
套接字API是Unix網絡的通用接口，允許使用各種網絡協議和地址。
下面列出了一些例子，在現在的 Linux 和 BSD 中一般都已經實現了。 
PF_LOCAL, PF_UNIX, PF_FILE
Local to host (pipes and file-domain)
PF_INET         IP protocol family
PF_AX25         Amateur Radio AX.25
PF_IPX          Novell Internet Protocol
PF_APPLETALK    Appletalk DDP
PF_NETROM       Amateur radio NetROM
PF_BRIDGE       Multiprotocol bridge
PF_ATMPVC       ATM PVCs
PF_X25          Reserved for X.25 project
PF_INET6        IP version 6
PF_ROSE         Amateur Radio X.25 PLP
PF_DECnet       Reserved for DECnet project
PF_NETBEUI      Reserved for 802.2LLC project
PF_SECURITY     Security callback pseudo AF
PF_KEY          PF_KEY key management API
PF_NETLINK, PF_ROUTE
routing API
PF_PACKET       Packet family
PF_ASH          Ash
PF_ECONET       Acorn Econet
PF_ATMSVC       ATM SVCs
PF_SNA          Linux SNA Project
PF_IRDA         IRDA sockets
PF_PPPOX        PPPoX sockets
PF_WANPIPE      Wanpipe API sockets
PF_BLUETOOTH    Bluetooth sockets
socket的通用address描述結構sockaddr是一個16字節大小的結構（2+14），sa_family可以認為是socket address family的縮寫。另外的14字節是用來描述地址。當指定sa_family=AF_INET之後，sa_data的形式也就被固定了下來：最前端的2字節用於記錄16位的端口，緊接著的4字節用於記錄32位的IP地址，最後的8字節清空為零。
struct sockaddr
{
unsigned short sa_family;
char sa_data14;
};
struct sockaddr_in //means socket address internet
{
unsigned short sin_family; //sin means socket (address) internet
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero8;
};
struct in_addr
{
unsigned long s_addr; // means source address
};

**使用TCP的服務器客戶機舉例**

**服務器**
設置一個簡單的TCP服務器涉及下列步驟：- 調用socket函數建立套接字，應當使用的參數參見例程。- 調用bind函數把套接字綁定到一個監聽端口上。注意bind函數需要接受一個sockaddr_in結構體作為參數，因此在調用bind函數之前, 程序要先聲明一個 sockaddr_in結構體,用memset函數將其清零，然後將其中的sin_family設置為AF_INET，接下來，程序需要設置其sin_port成員變量，即監聽端口。需要說明的是，sin_port中的端口號需要以網絡字節序存儲，因此需要調用htons函數對端口號進行轉換（函數名是"host to network short"的縮寫）。- 調用listen函數，使該套接字成為一個處在監聽狀態的套接字。- 接下來，服務器可以通過accept函數接受客戶端的連接請求。若沒有收到連接請求，accept函數將不會返回並阻塞程序的執行。接收到連接請求後，accept函數會為該連接返回一個套接字描述符。accept函數可以被多次調用來接受不同客戶端的連接請求，而且之前的連接仍處於監聽狀態——直到其被關閉為止。- 現在，服務器可以通過對send，recv或者對write，read等函數的調用來同客戶端進行通信。- 對於一個不再需要的套接字，可以使用close函數關閉它。 Note that if there were any calls to fork(), each process must close the sockets it knew about (the kernel keeps track of how many processes have a descriptor open), and two processes should not use the same socket at once.
/* Server code in C */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(void)
{
struct sockaddr_in stSockAddr;
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(-1 == SocketFD)
{
perror("can not create socket");
exit(EXIT_FAILURE);
}

memset(&stSockAddr, 0, sizeof(struct sockaddr_in));

stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(1100);
stSockAddr.sin_addr.s_addr = INADDR_ANY;

if(-1 == bind(SocketFD,(const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)))
{
perror("error bind failed");
close(SocketFD);
exit(EXIT_FAILURE);
}

if(-1 == listen(SocketFD, 10))
{
perror("error listen failed");
close(SocketFD);
exit(EXIT_FAILURE);
}

for(;;)
{
int ConnectFD = accept(SocketFD, NULL, NULL);

if(0 > ConnectFD)
{
perror("error accept failed");
close(SocketFD);
exit(EXIT_FAILURE);
}

/* perform read write operations ... */

shutdown(ConnectFD, SHUT_RDWR);

close(ConnectFD);
}
close(SocketFD);
return 0;
}
Python實現：
from socket import from time import ctime
HOST=
PORT=1100
BUFSIZ=1024
ADDR=(HOST, PORT)
sock=socket(AF_INET, SOCK_STREAM)
sock.bind(ADDR)
sock.listen(5)
while True:
print('waiting for connection')
tcpClientSock, addr=sock.accept()
print('connect from ', addr)
while True:
try:
data=tcpClientSock.recv(BUFSIZ)
except:
print(e)
tcpClientSock.close()
break
if not data:
break
s='Hi,you send me :%s %s' %(ctime(), data.decode('utf8'))
tcpClientSock.send(s.encode('utf8'))
print(ctime(), ':', data.decode('utf8'))
tcpClientSock.close()
sock.close()

**客戶機**
建立一個客戶機連接涉及以下步驟：- 調用 socket()建立套接字。- 用connect()連接到服務器,類似服務器端的操作，將一個sin_family設為AF_INET,sin_port設為服務器的監聽端口（依然要以網絡字節序）,sin_addr設為服務器IP地址的（還是要用網絡字節序）的sockaddr_in作為參數傳入。
*用send() 和 recv() 或者 write() 和 read()進行通信。- 用close()終止連接。如果調用fork(), 每個進程都要用close()。
/* Client code in C */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(void)
{
struct sockaddr_in stSockAddr;
int Res;
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if (-1 == SocketFD)
{
perror("cannot create socket");
exit(EXIT_FAILURE);
}

memset(&stSockAddr, 0, sizeof(struct sockaddr_in));

stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(1100);
Res = inet_pton(AF_INET, "192.168.1.3", &stSockAddr.sin_addr);

if (0 > Res)
{
perror("error: first parameter is not a valid address family");
close(SocketFD);
exit(EXIT_FAILURE);
}
else if (0 == Res)
{
perror("char string (second parameter does not contain valid ipaddress");
close(SocketFD);
exit(EXIT_FAILURE);
}
if (-1 == connect(SocketFD, (const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)))
{
perror("connect failed");
close(SocketFD);
exit(EXIT_FAILURE);
}

/* perform read write operations ... */

shutdown(SocketFD, SHUT_RDWR);

close(SocketFD);
return 0;
}
Python實現：
from socket import 
HOST='192.168.1.3'
PORT=1100
BUFSIZ=1024
ADDR=(HOST, PORT) 
client=socket(AF_INET, SOCK_STREAM)
client.connect(ADDR)
while True:
data=input('>')
if not data:
break
client.send(data.encode('utf8'))
data=client.recv(self.BUFSIZ)
if not data:
break
print(data.decode('utf8'))

**使用UDP的服務器客戶機舉例**
用戶數據報協議（UDP）是一個不保證正確傳輸的無連接協議。 UDP數據包可能會亂序到達，多次到達或者直接丟失。但是設計的負載比TCP小。 
UDP地址空間，也即是UDP端口，和TCP端口是沒有關係的。

**服務器**
Code may set up a UDP server on port 7654 as follows:
#include 
#include 
#include 
#include 
#include 
#include 
#include  /* for close() for socket */ 
#include 
int main(void)
{
int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in sa; 
char buffer1024;
ssize_t recsize;
socklen_t fromlen;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = htons(7654);

if (-1 == bind(sock,(struct sockaddr *)&sa, sizeof(struct sockaddr)))
{
perror("error bind failed");
close(sock);
exit(EXIT_FAILURE);
} 
for (;;) 
{
printf ("recv test....\n");
recsize = recvfrom(sock, (void *)buffer, 1024, 0, (struct sockaddr *)&sa, &fromlen);
if (recsize 
上面的無限循環用recvfrom()接收給UDP端口7654的數據包。使用如下參數：- 指向緩存數據指針- 緩存大小
*標誌
*地址- 地址結構體大小
同樣功能的Python實現：
import socket
port=7654
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#從指定的端口，從任何發送者，接收UDP數據
s.bind((,port))
print('正在等待接入...')
while True:
#接收一個數據
data,addr=s.recvfrom(1024)
print('Received:',data,'from',addr)

**客戶機**
用UDP數據包發送一個"Hello World!" 給地址127.0.0.1（迴環地址），端口 7654 。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  /* for close() for socket */

int main(int argc, char *argv)
{
int sock;
struct sockaddr_in sa;
int bytes_sent, buffer_length;
char buffer200;

buffer_length = snprintf(buffer, sizeof(buffer), "Hello World!");

sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (-1 == sock) /* if socket failed to initialize, exit */
{
printf("Error Creating Socket");
exit(EXIT_FAILURE);
}

memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(0x7F000001);
sa.sin_port = htons(7654);

bytes_sent = sendto(sock, buffer, buffer_length, 0,(struct sockaddr*)&sa, sizeof (struct sockaddr_in));
if (bytes_sent 
buffer指定要發送數據的指針,  buffer_length指定緩存內容的大小。
同樣功能的Python實現：
import socket
port=7654
host='localhost'
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.sendto(b'Hello World!',(host,port))

**參見**
計算機網絡
*Winsock

**參考資料**
The "de jure" standard definition of the Sockets interface is contained in the POSIX standard, known as:
*IEEE Std. 1003.1-2001 Standard for Information Technology—Portable Operating System Interface (POSIX).
*Open Group Technical Standard: Base Specifications, Issue 6, December 2001.- ISO/IEC 9945:2002
Information about this standard and ongoing work on it is available from  the Austin websitedate=20090918101223 .
The IPv6 extensions to the base socket API are documented in RFC 3493 and RFC 3542.

**外部連結**
手冊頁
** accept(2)date=20070625054735 
** connect(2)date=20070608143106 - Beej's Guide to Network Programmingdate=20110410094952  - 2007
** Beej's Guide to Network Programming 正體中文版（zh-tw）date=20200305064407  - 2014
** Beej's Guide to Network Programming 簡體中文版（zh-cn）date=20200305064324  - 2014- UnixSocket FAQdate=20090502044217 - Get system IP list - C++ Example- quick TCP-IP NetIntro with C examplesdate=20090126215359 - Porting Berkeley Socket programs to Winsockdate=20080423001348  - Microsoft's documentation.- Programming UNIX Sockets in C - Frequently Asked Questionsdate=20090927132754  - 1996- Linux network programmingdate=20090929004701  - Linux Journal, 1998