socket客户/服务器模型

image.png

用到的函数

socket函数

image.png
流式套接字就是TCP,数据包套接字就是UDP
一个程序最多打开一般来说是1024个文件描述符,由一个系统的参数来确定的,叫open files。

bind函数

image.png

listen函数

image.png
image.png
image.png
image.png

accept函数

在完成连接队列为空时,accept会阻塞

  • 第二个和第三个参数,要么都是空指针,要么都不是空指针

image.png

connect函数

image.png
image.png

read函数

image.png

write函数

image.png

例子

客户端编程

  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <errno.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <string.h>
  10. int main(){
  11. int sock;
  12. if(sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) < 0)//其实前两个已经表示为是tcp协议了,第三个参数可以填0
  13. {
  14. ERR_EXIT("socket");//报错误的宏
  15. }
  16. struct sockaddr_in servaddr;
  17. memset(&servaddr, 0, sizeof(servaddr));//全部填充0
  18. servaddr.sin_family = AF_INET;
  19. servaddr.sin_prot = htons(5188);
  20. servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  21. if(connect(sock, (struct sockaddr*)servaddr, sizeof(servaddr)) < 0){
  22. ERR_EXIT("connect");
  23. }
  24. char recvbuf[1024] = {0};
  25. char sendbuf[1024] = {0};
  26. while(fgets(sendbuf, sizeof(sendbuf), stdin)!= NULL){
  27. write(sock, sendbuf, strlen(sendbuf));
  28. read(sock, recvbuf, sizeof(recvbuf));
  29. fputs(recvbuf, stdout);
  30. memset(sendbuf, 0, sizeof(sendbuf));//清空缓存区
  31. memset(recvbuf, 0, sizeof(recvbuf));
  32. }
  33. close(sock);
  34. return 0;
  35. }

服务器编程

监听套接字:listenfd
已连接套接字:conn
注意这里listen之后,客户端就已经能够搜索到了

  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <errno.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <string.h>
  10. int main(){
  11. int listenfd;
  12. if(listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) < 0)//其实前两个已经表示为是tcp协议了,第三个参数可以填0
  13. {
  14. ERR_EXIT("socket");//报错误的宏
  15. }
  16. struct sockaddr_in servaddr;
  17. memset(&servaddr, 0, sizeof(servaddr));//全部填充0
  18. servaddr.sin_family = AF_INET;
  19. servaddr.sin_prot = htons(5188);
  20. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//参数表示本机的任意地址,以下两种也是正确的写法
  21. //servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  22. //inet_aton("127.0.0.1", &servaddr.sin_addr);
  23. if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){//一旦绑定完成,这个套接字就会被认为是被动套接字,否则是主动套接字。
  24. ERR_EXIT("bind");
  25. }
  26. if(listen(listenfd, SOMAXCONN) < 0)//后面的宏,代表队列的最大值
  27. {
  28. ERR_EXIT("listen");
  29. }
  30. struct sockaddr_in peeraddr;
  31. socklen_t peerlen = sizeof(peeraddr);
  32. int conn;
  33. if((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0){//这里返回值是文件描述符
  34. ERR_EXIT("accept");
  35. }
  36. char recvbuf[1024];
  37. while(1){
  38. memset(recvbuf, 0, sizeof(recvbuf));
  39. int ret = read(conn, recvbuf, sizeof(recvbuf));
  40. fputs(recvbuf, stdout);
  41. write(conn, recvbuf, ret);
  42. }
  43. close(conn);
  44. close(listenfd);
  45. return 0;
  46. }