什麼是套接字:
套接字是一種通信過程,它使客戶/服務器系統的開發工作既可以在本地單機上進行,也可以跨網絡進行。
套接字建立過程:
1,創建一個套接字,這是分配給該服務器進程的一個操作系統資源,套接字由服務器通過系統調用socket創建出來的,所以其它進程將不能對它進行訪問。
2,給套接字起個名字,用系統調用bind,然後服務器就開始等待有客戶連接到這個命名套接字上來。系統調用listen創建一個隊列,來自客戶的連接將在這個隊列上排隊等待服務器的處理,服務器將通過系統調用accept來接受來自客戶的接入連接。
3,當服務器調用accept的時候,會新創建一個套接字,新套接字的唯一用途就是與這個特定的客戶進行通信,而命名套接字則被解放出來,準備處理來自其它客戶的連接。
客戶端:
先通過調用socket創建一個未命名的套接字,然後調用connect利用服務器的命名套接字和一個地址來建立一個連接。
套接字建立後,可以像操作底層文件描敘符一樣用它來實現數據通信。
一個簡單的服務器端:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
int main()
{
int server_sockfd,client_sockfd;
int server_len,client_len;
struct sockadd_un server_address;
struct sockadd_un client_address;
/////////刪除以前的套接字,再爲服務器創建一個未命名套接字////////
unlink("server_socket");
server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
///////// 給套接字起名字 //////////////////
server_address.sun_family = AF_UNIX;
stycpy(server_address.sun_path, "server_socket");
server_len = sizeof(server_address);
bind(server_sockfd,(struct sockaddr *)&server_address,server_len);
/////////創建一個連接隊列,開始等待客戶的到來 ////
listen(server_sockfd, 5);
while(1){
char ch;
printf("server waiting/n");
/////////接受一個連接 /////////////////////////////////////////////
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,(struct sockadd *)&client_address, &client_len);
//////////對client_sockfd套接字上的客戶進行讀寫///////////////////
read(client_sockfd,&ch,1);
ch++;
write(client_sockfd,&ch,1);
close(client_sockfd);
}
}
一個簡單的客戶端:
#include <stdio.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <unistd.h>
int main()
{
int sockfd;
int len;
struct sockaddr_un address;
int result;
char ch = 'a';
//////爲客戶創建一個套接字/////////////////
sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
//////根據服務器設置的情況給這個套接字起個名字/////////////
address.sun_family = AF_UNIX;
stycpy (address.sun_path, "server_socket");
len = sizeof(address);
///////把套接字連接到服務器的套接字///////////////////////
result = connect (sockfd, (struct sockaddr *)&address,len);
if(result == -1)
{perror("oops:client1");
exit(1);
}
///////讀寫操作///////////////////////////////////////////
write(sockfd,&ch,1);
read(sockfd,&ch,1);
printf("char from server = %c/n",ch);
close(sockfd);
exit(0);
}
詳細說明:
創建一個套接字:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain,int type ,int protocol);
創建出來的套接字是一條通信線路的一個端點。domain參數負責指定地址族,type參數負責指定與這個套接字一起使用的通信類型,而Portocol參數負責指定所使用的協議。
domain:參數可以使用的域如表:
AF_UNIX: UNXI內部(文件系統套接字)
AF_INET: APRA因特網協議(UNIX網絡套接字)
AF_ISO: ISO標準協議
AF_NS: 施樂網絡系統協議
AF_IPX: novell IPX協議
AF_APPLETALK: Appletalk DDS
type:指定了與新套接字對應的通信特性。它的取值包括SOCK_STREAM和SOCK_DGRAM。
SOCK_STREAM是一個有序的,可靠的,基於連接的雙向字節流。TCP協議
SOCK_DGRAM是一個數據圖服務。無保證的連接,對於AF_INET域使用UDP協議
protocol:通信所用的協議通常是由套接字的類型和套接字的域來決定的,一般不再有可挑選的餘地,如果還能挑選,就需要用到protocol參數,0選擇缺省的協議。
socket系統調用返回的是一個描敘符,它在許多方面類似於一個底層的文件描敘符。
套接字地址:
每個套接字域都有它自己的地址格式,
AF_UNIX套接字的地址是一個定義在sys/un.h頭文件裏的sockaddr_un結構:
struct sockaddr_un{
sun_family_t sun_family;
char sun_path[ ];
};
AF_INET套接字的地址是一個定義在netinet/in.h頭文件裏的sockaddr_in結構確定的。
struct sockaddr_in{
short int sin_family;
unsigned shor int sin_port;
struct in_addr sin_addr;
};
IP地址結構in_addr被定義爲:
struct in_addr{
unsigned long int s_addr;
};
給套接字起名字:
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *address,size_t address_len);
作用:把參數address中給出的地址賦值給與文件描敘符socket相關聯的未命名的套接字。地址結構的長度是通過address_len參數傳遞的。
創建套接字隊列:
#include <sys/socket.h>
int listen(int socket,int backlog);
backlog爲最大隊列長度,常用的值是5;
接受連接:
#include <sys/socket.h>
int accept(int socket,struct sockaddr * address,size_t *address_len);
accept調用會等到有客戶程序試圖連接到由socket參數指定的套接字時才返回。該客戶就是排在隊列第一位的連接。accept函數將創建出一個新的套接字來與客戶進行通信,返回的是與之對應的文件描敘符。新套接字的類型與服務器監聽套接字的類型是一樣的。
請求連連:
#include <sys/socket.h>
int connect(int socket,const sockaddr *address,size_t address_len);
參數socket指定的套接字將連接到參數address指定的服務器套接字上去。
關閉套接字int close ( int socket);
select調用:
#include <sys/types.h>
#include <sys/time.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds,struct timeval *timeout);
select調用的作用是檢查那個文件描敘符集合裏是否有一個文件描敘符處於讀操作就緒狀態,寫操作就緒或有個錯誤排隊的狀態,如果沒有,就阻塞到這些狀態有一個出現爲止。
nfds參數給出了需要進行測試的文件描敘符個數,測試將對第0到第(nfds-1)個描述符進行。三個描述符集合都可以是一個空指針,這表示不進行相應的測試。