一.TCP編程API
1.socket函數
1.socket函數
include include
int socket(int domain,int type,int protocol);
? ? 參數
? ? ? ? domain
? ? ? ? AF_INET
? ? ? ? AF_INET6
? ? ? ? AF_UNIX,AF_LOCAL
? ? ? ? AF_NETLINK
? ? ? ? AF_PACKET
? ? type
? ? ? ? SOCK_STREAM: 流式套接字,唯一對應于TCP
? ? ? ? SOCK_DGRAM:數據報套接字,唯一對應著UDP
? ? ? ? SOCK_RAW:原始套接字
? ? protocol
? ? ? ? 一般填0,原始套接字編程時需填充
? ? 返回值
? ? ? ? 成功返回文件描述符
? ? ? ? 出錯返回-1
? ? ? ? 如果是IPV6編程,要使用struct sockddr_in6結構體(man 7 IPV6),通常使用struct ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? sockaddr_storage來編程。
int socket(int domain,int type,int protocol);參數domainAF_INETAF_INET6AF_UNIX,AF_LOCALAF_NETLINKAF_PACKETtypeSOCK_STREAM: 流式套接字,唯一對應于TCPSOCK_DGRAM:數據報套接字,唯一對應著UDPSOCK_RAW:原始套接字protocol一般填0,原始套接字編程時需填充返回值成功返回文件描述符出錯返回-1如果是IPV6編程,要使用struct sockddr_in6結構體(man 7 IPV6),通常使用struct ? ? ? ? ? ? ? ? ? ? ? ?sockaddr_storage來編程。
2.bind函數
2.bind函數
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)
? ? 參數
? ? ? ? sockfd:通過socket()函數拿到的fd
? ? ? ? addr:采用struct sockaddr的結構體地址,通用結構體
? ? ? ? struct sockaddr
? ? ? ? ?{
? ? ? ? ? ? sa_family_t sa_family;
? ? ? ? ? ? char sa_data[4];
? ? ? ? ?}
? ? ? ? struct sockaddr_in{ 基于Internel通信結構體
? ? ? ? ? ? as_family_t sin_family;
? ? ? ? ? ? in_port_t sin_port;
? ? ? ? ? ? struct in_addr sin_addr;
? ? ? ? ? ? sin_zero , //填充字節,需清零
? ? ? ? ? ? }
? ? ? ? struct in_addr{
? ? ? ? ? ? uint32_t s_addr;
? ? ? ? ? ? }
? ? ? ? addrlen:地址長度
2.bind函數
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)參數sockfd:通過socket()函數拿到的fdaddr:采用struct sockaddr的結構體地址,通用結構體struct sockaddr{sa_family_t sa_family;char sa_data[4];}struct sockaddr_in{ 基于Internel通信結構體as_family_t sin_family;in_port_t sin_port;struct in_addr sin_addr;sin_zero , //填充字節,需清零}struct in_addr{uint32_t s_addr;}addrlen:地址長度
3.listen函數
3.listen()函數
int listen(int sockfd,int backlog);
? ? 參數:
? ? ? ? sockfd: 通過socket()函數拿到的fd;
? ? ? ? backLog:同時允許幾路客戶端和服務器進行正在連接的過程(正在三次握手),一般填5。
? ? ? ? ? ? 內核中服務器的套接字fd會維護2個鏈表
? ? ? ? ? ? ? ? 1.正在三次握手的客戶端鏈表(數量=2*backlog+1)
? ? ? ? ? ? ? ? 2.已經建立好連接的客戶端鏈表(已經完成三次握手分配好了的newfd)
? ? ? ? 返回值:
? ? ? ? ? ? ? ? 成功返回0
? ? ? ? ? ? 出錯返回-1
? ? listen(fd,5);//表示系統允許11(2*5+1)個客戶端同時進行三次握手
3.listen()函數
int listen(int sockfd,int backlog);參數:sockfd: 通過socket()函數拿到的fd;backLog:同時允許幾路客戶端和服務器進行正在連接的過程(正在三次握手),一般填5。內核中服務器的套接字fd會維護2個鏈表1.正在三次握手的客戶端鏈表(數量=2*backlog+1)2.已經建立好連接的客戶端鏈表(已經完成三次握手分配好了的newfd)返回值:成功返回0出錯返回-1listen(fd,5);//表示系統允許11(2*5+1)個客戶端同時進行三次握手
4.accept函數
4.accept()函數
阻塞等待客戶端連接請求int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);參數sockfd:經過前面socket()創建并通過bind(),listen()設置過的fdaddr:指向存放地址信息的結構體的首地址獲取客戶端IP地址和端口號addrlen:存放地址信息的結構體的大小返回值成功,返回已經建立連接的新的newfd出錯,返回-1
5.客戶端連接函數connect
5.客戶端連接函數connect()
int connect (int sockfd, struct sockaddr * serv_addr, int addrlen)參數:sockfd:通過socket()函數拿到的fdaddr:struct sockaddr的結構體變量地址addrlen:地址長度返回值:成功,返回0失敗,返回-1
二.編程
socket函數編寫
用將socket函數的返回值給fd,通過fd是否小于零來判斷是否成功
bland函數
第一個參數是socket()拿到的fd
sockaddr_in? 結構體
第二個參數是結構體,需先定義 sockaddr_in? 結構體
定義之后在填充之前還需要將結構體清零 ,用bzero函數清零
清零之后去初始化結構體
man 2 bind 往下滑找到 socket,它是在man 7 ip,去man 7 ip 中找到我們填充的sockaddr_in結構體,發現它初始化用的是AF_INET
初始化之后去寫結構體的第二個參數sin_port的ip地址,可以去宏定義,5000以前是內核相關的,為了防止沖突寫5001
SERV_IP_ADDR通過ifconfig查看
?sin_port用的是本地字節,需要轉換成網絡字節,用u_short htons(u_short short)主機字節序到網絡字節序
結構體第三個參數
sin_addr 又指向s_addr,也是要轉換成網絡節字
sockaddr_in結構體也可以使用另一種方式初始化與配置
將sockaddr_in結構體轉化成sockaddr結構體
bind函數成功返回0,失敗返回-1
去判斷是否成功
listen函數
accept函數
TCP服務器讀取內容
接著上一章TCP學習所寫的代碼寫 read函數代碼
read成功返回字節數,失敗返回-1
在do-while循環里不斷讀取accept函數接收到的數據,當小于-1就退出
后兩個if作用是判斷是否還在接收字節,沒有就退出
第三個if 是客戶端是否主動要退出如果是就退出