由于套接字编程是很庞大的,本文作为学习笔记也仅仅实现了较为简单和基础的部分,但是希望对大家有帮助
所有计算机网络学习笔记链接
套接字在标识通信端点的时候是不同的
对外: 使用IP地址+端口号对内:使用套接字描述符进行标识
套接字地址结构:
//IP socket address structure
//sockaddr_in: 因特网套接字地址
struct sockaddr_in {
uint_16_t sin_family; //协议族
uint_16_t sin_port; //端口
struct in_addr sin_addr; //32位的IP地址
unsigned char sin_zero[8]; //sizeof (struct sockaddr)
}
//用于:connect, bind, accept
struct sockaddr {
uint16_t safamily;
char sa_data[14];
}
socke函数讲解 cocket在connect, bind, accept函数中要求一个指向与协议相关的套接字地址结构指针,我们通过设置一个通用的sockaddr数据结构指针,然后标明套接字地址的时候进行强制转换成为这个通用的指针(使之能够接受各种类型的套接字地址结构)
创建一个套接字,函数如下
AF_INET表明我们正在使用32位的IP地址
#includebind#include int socket(int domain, int type, int protocol) #成功返回非负描述符号, 出错返回-1 #实例 clientfd = socket(SF_INET, SOCK_STREAM, 0); //default : 0
下面的bind, listen, accept: 服务器使用这些函数来同客户端建立连接
bind函数告诉内核将addr中的服务器套接字地址和套接字描述符号sockfd联系起来
#includelistenint bind(int sockfd, const struct sockaddr * addr, socklen_t addrlen); #成功返回0 出错返回 -1
listen函数用与告诉内核:套接字描述符号是被 服务器而不是 客户端所使用的
listen函数将sockfd从一个主动套接字转化为一个监听套接字,这个套接字接收客户端的请求。
backlog就指明了排队连接的数目
#includeacceptint listen(int sockfd, int backlog); #成功就返回0 否则就返回 -1
服务器通过调用accept函数来等待来自客户端的连接请求
返回的是 非负连接描述符号(已连接描述符),就是创建了一个新的套接字单独的和客户端套接字进行通信连接。原本的 监听描述符继续等待新的客户端的申请,这样就可以同时处理很多的客户端申请了
#includeint accept(int listenfd, struct sockaddr * addr, int * addrlen); #成功就返回 非负连接描述符号,出错就返回 -1
read & write 函数, 叫法不一样,就是进行二者的交互嘛
#read用于读取数据 ssize_t read (int fd, void * buf, size_t count); #write 用于写数据, 同样也是阻塞式的 ssize_t write(int fd, const void * buf, size_t count);
客户端通过调用connect函数来建立和套接字地址为addr的服务器之间的连接
connec函数会发生阻塞:直到连接成功或者是发生了错误
int connect (int clientfd, const struct sockaddr * addr, socklen_t addrlen);主机字节序和网络字节序相互转换
为了使程序在不同的主机之间传输的时候得到正确的解释女️,需要进行字节序的转换
uint32_t htonl(uint32_t hostlong); //32位主机转网络 uint16_t htons(uint16_t hostshort); //16位主机转网络 uint32_t ntohl(uint32_t netlong); //32位网络转主机 uint16_t ntohs(uint16_t netshort); //16位网络转主机套接字案例
点对点的一个客户端发送信息给服务器端,然后服务器端将内容复制后重新发送的场景
s e r v e r . c server.c server.c
#include#include #include #include #include #include #include #include #include #include const int MYPORT = 8887; const int QUEUE = 20; const int BUFFER_SIZE = 20; //Server_addr : 指明远程的IP地址和端口号码 int main() { //创建了套接字 int server_sockfd = socket(AF_INET, SOCK_STREAM, 0); //定义sockaddr_in struct sockaddr_in server_sockaddr; server_sockaddr.sin_family = AF_INET; server_sockaddr.sin_port = htons(MYPORT); //端口的转换函数 server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址 //bind 成功返回0,出错返回 -1 if (bind(server_sockfd, (struct sockaddr *) & server_sockaddr, sizeof(server_sockaddr)) == -1) { perror("bind"); exit(1); } printf ("监听:%d端口n", MYPORT); //listen成功的话返回0 , 出错返回 -1 if (listen(server_sockfd, QUEUE) == -1) { perror("listen"); exit(1); } //客户端套接字 char buffer[BUFFER_SIZE]; struct sockaddr_in client_addr; //用来标识客户端的结构体 socklen_t length = sizeof (client_addr); printf("等待客户端连接n"); //成功 -> 返回非负 //失败 -> 返回-1 int conn = accept(server_sockfd, (struct sockaddr*) & client_addr, & length); if (conn < 0) { perror("connect"); exit(1); } printf("客户端成功连接n"); while (1) { memset(buffer, 0, sizeof (buffer)); int len = recv(conn, buffer, sizeof (buffer), 0); //客户端发送exit时候进行终止退出 if (strcmp (buffer, "exitn") == 0 || len <= 0) { break; } printf("来自客户端的数据:%sn", buffer); send(conn, buffer, len, 0); printf("发送给客户端的数据:%sn", buffer); } close(conn); close(server_sockfd); return 0; }
c l i e n t . c client.c client.c
#include参考资料#include #include #include #include #include #include #include #include #include #define MYPORT 8887 #define BUFFER_SIZE 1024 char * SERVER_IP = "127.0.0.1"; int main() { //定义sockfd int sock_cli = socket(AF_INET, SOCK_STREAM, 0); //定义一下sockaddr_in struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof (servaddr)); servaddr.sin_family = AF_INET; //定义协议族 servaddr.sin_port = htons(MYPORT); servaddr.sin_addr.s_addr = inet_addr(SERVER_IP); //服务器IP printf("连接%s: %dn", SERVER_IP, MYPORT); //连接服务器,成功返回0 错误返回-1 if (connect(sock_cli, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { perror("connectn"); exit(1); } printf("服务器连接成功!n"); //建立了同服务器端新创建的套接字的连接 char sendbuf[BUFFER_SIZE]; char recvbuf[BUFFER_SIZE]; while (fgets(sendbuf, sizeof (sendbuf), stdin) != NULL ) { printf("向服务器发送数据: %sn", sendbuf); send(sock_cli, sendbuf, strlen(sendbuf), 0); if (strcmp(sendbuf,"exitn") == 0) { break; //输入exit就退出了 } recv(sock_cli, recvbuf, sizeof(recvbuf), 0); printf("从服务器接收数据:%sn", recvbuf); memset(sendbuf, 0, sizeof (sendbuf)); memset(recvbuf, 0, sizeof (recvbuf)); } close(sock_cli); return 0; }
https://blog.csdn.net/weixin_44164489/article/details/108606391
https://blog.csdn.net/chengqiuming/article/details/89298442



