簡單介紹了套接字(Sockets)編程的基本概念
套接字(socket)作用
在任何通信中降铸,都有一個發(fā)送者和一個接收者啃匿,發(fā)送者和接收者是通信的兩端貌矿,也被稱為通信
的終端(communication endpoint), sockets是通信終端(communication endpoint)的一種抽
象,sockets設(shè)計用于網(wǎng)絡(luò)通信铺浇,網(wǎng)絡(luò)協(xié)議有很多種,這里主要以TCP協(xié)議為例介紹
套接字描述符(socket descriptor)
我們可以通過一個文件描述符(file descriptor)訪問文件垛膝,類似地鳍侣,我們也是通過套接字描
述符(socket descriptor)來訪問socket。不僅如此吼拥,在Unix中倚聚,socket descriptor
就是
通過file descriptor
實現(xiàn)的,對file descriptor
的讀凿可、寫函數(shù)(read write)完全適用于
socket descriptor
惑折。
不過相對于文件的讀寫,對socket的讀寫含義有小區(qū)別,讀一個socket就是讀取對方發(fā)送給
我們的數(shù)據(jù)唬复,寫一個socket就是向?qū)Ψ桨l(fā)送數(shù)據(jù)
創(chuàng)建套接字函數(shù)
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
- domain 表示通信的屬性矗积,包含通信地址格式全肮,POSIX中定義的取值有:
AF_INET
(ipv4)
敞咧、AF_INET6
(ipv6)、AF_UNIX
(unix)辜腺、AF_UNSPEC
(未指定) - type表示通信的類型休建,對于TCP通信,該字段為
SOCKET_STREAM
- protocol表示使用的通信協(xié)議
綁定通信地址
通信時需要綁定一個地址评疗,這樣不同的通信之間使用各自的地址测砂,互相干擾。綁定地址的時候
可以選擇使用系統(tǒng)自動分配的地址百匆,也可以手動綁定砌些。
在常見的客戶端和服務(wù)端通信模型中,客戶端可以讓使用系統(tǒng)自動分配的地址加匈,服務(wù)端則需要
顯示綁定一個地址存璃,這樣客戶端才能知道和哪個地址建立連接。
手動綁定地址的函數(shù)是:
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
建立連接
建立連接的三步驟
- 服務(wù)端就緒雕拼,等待客戶端的連接
#include <sys/socket.h>
int listen(int sockfd, int backlog);
- 客戶端請求建立連接
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
- 服務(wù)端接受連接
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);
讀寫數(shù)據(jù)
可以適用和讀寫文件一樣的函數(shù)纵东,也可以使用socket專有的
例子
- 服務(wù)端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int
main(int argc, char *argv[])
{
socklen_t clilen;
int n;
//創(chuàng)建一個服務(wù)端的socket
int serverfd = socket(AF_INET, SOCK_STREAM, 0);
if (serverfd < 0)
error("ERROR opening socket");
//初始化服務(wù)端地址
struct sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
//端口號使用9002
serv_addr.sin_port = htons(9002);
//綁定服務(wù)端地址
if (bind(serverfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
//等待客戶端連接
listen(serverfd, 5);
//客戶端地址
struct sockaddr_in cli_addr;
clilen = sizeof(cli_addr);
//接受客戶端連接
int clientfd = accept(serverfd, (struct sockaddr *) &cli_addr, &clilen);
if (clientfd < 0)
error("ERROR on accept");
char buffer[256] = {0};
//讀取客戶端發(fā)送的信息
n = read(clientfd, buffer, 255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
close(serverfd);
close(clientfd);
return 0;
}
- 客戶端
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
printf("client is start....\n");
int n;
//創(chuàng)建客戶端socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
//初始化服務(wù)端地址
struct sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(9002);
//請求建立連接
if (connect(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("connect to server");
//發(fā)送數(shù)據(jù)
char buffer[256] = "hi~";
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
close(sockfd);
return 0;
}