套接字程式設計(一)----基於TCP協議
套接字(socket):可以看做是不同主機之間的程序進行雙向通訊的端點,即通訊的兩方的一種約定,用套接字中的相關函式來完成通訊過程。
**socket=Ip Address+TCP/UDP+port
三次握手建立連線
當客戶端呼叫connect時,觸發了連線請求,向伺服器傳送了SYN J包,這時connect進入阻塞狀態;伺服器監聽到連線請求,即收到SYN J包,呼叫accept函式接收請求向客戶端傳送SYN K ,ACK J+1,這時accept進入阻塞狀態;客戶端收到伺服器的SYN K ,ACK J+1之後,這時connect返回,並對SYN K進行確認;伺服器收到ACK K+1時,accept返回,至此三次握手完畢,連線建立。
四次揮手釋放連線
1、某個應用程序首先呼叫close主動關閉連線,這時TCP傳送一個FIN M;
2、另一端接收到FIN M之後,執行被動關閉,對這個FIN進行確認。它的接收也作為檔案結束符傳遞給應用程序,因為FIN的接收意味著應用程序在相應的連線上再也接收不到額外資料;
3、一段時間之後,接收到檔案結束符的應用程序呼叫close關閉它的socket。這導致它的TCP也傳送一個FIN N;
4、接收到這個FIN的源傳送端TCP對它進行確認。
以下庫函式做⽹網路位元組序和主機位元組序的轉換。
h—-host主機
n—-net網路
l —-32位長整數
s —-16位短整數
例 :htonl表示將32位的長整數從主機位元組序轉換為網路位元組序,例如將IP地址轉換後準備傳送。如果 主機是小端位元組序,這些函式將引數做相應的大小端轉換然後返回,如果主機是大端位元組序,這些函式不做轉換,將引數原封不動地返回。
1、建立socket
domain:協議域,協議域決定了socket的地址型別,在通訊中必須採用對應的地址,AF_INET決定了要用ipv4地址(32位的)與埠號(16位的)的組合如下:
type:指socket型別。流式Socket(SOCK_STREAM)是一種面向連線的Socket,針對於面向連線的TCP服務應用。資料報式Socket(SOCK_DGRAM)是一種無連線的Socket,對應於無連線的UDP服務應用。。
protocal:一般設為0,會自動選擇第二個引數型別對應的預設協議。
2、繫結bind
socket:一個套接字描述符。
address:一個sockaddr結構指標,該結構中包含了要結合的地址和埠號。
address_len:確定address緩衝區的長度。
3、listen監聽,第二個引數為最大連線數,一般設為10。
4、accept函式在套介面接受連線
5、connect函式,用於建立與指定外部埠的連線,
伺服器端:
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int startup(const char *_ip,int _port)
{
//create socket
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
return 2;
}
//bind
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=inet_addr(_ip);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
return 3;
}
//listen
if(listen(sock,10)<0)
{
perror("listen");
return 4;
}
return sock;
}
static void usage(const char *proc)
{
printf("usage:[ip] [port]\n",proc);
}
int main(int argc,char *argv[])
{
if(argc!=3)
{
usage(argv[0]);
return 1;
}
int listen_sock=startup(argv[1],atoi(argv[2]));
struct sockaddr_in remote;
socklen_t len=sizeof(remote);
char buf[1024];
while(1)
{
int sock=accept(listen_sock,(struct sockaddr*)&remote,&len);
if(sock<0)
{
perror("accept");
continue;
}
printf("client ip: %s, port: %d\n",inet_ntoa(remote.sin_addr),ntohs(remote.sin_port));
while(1)
{
ssize_t s=read(sock,buf,sizeof(buf)-1);
if(s>0)
{
buf[s]=0;
printf("client say:%s\n",buf);
write(sock,buf,strlen(buf));
}
}
}
return 0;
}
客戶端
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
static void usage(const char *proc)
{
printf("%s [server_ip] [server_port]\n",proc);
}
int main(int argc,char *argv[])
{
if(argc!=3)
{
usage(argv[0]);
return 1;
}
//create socket
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
return 2;
}
//connect
struct sockaddr_in peer;
peer.sin_family=AF_INET;
peer.sin_port=htons(atoi(argv[2]));
peer.sin_addr.s_addr=inet_addr(argv[1]);
if(connect(sock,(struct sockaddr*)&peer,sizeof(peer))<0)
{
perror("connect");
return 3;
}
char buf[1024];
while(1)
{
printf("please enter:");
fflush(stdout);
ssize_t s=read(0,buf,sizeof(buf)-1);
if(s>0)
{
buf[s-1]=0;
write(sock,buf,strlen(buf));
ssize_t _s=read(sock,buf,sizeof(buf)-1);
if(_s>0)
{
buf[_s]=0;
printf("server echo:%s\n",buf);
}
}
}
close(sock);
return 0;
}