服务器/客户端的简单例子

服务器/客户端的简单例子

read()/write()函数代码
服务器代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <unistd.h>
  7. #include <linux/in.h>
  8. #define PORT 8888 //prot
  9. #define BACKLOG 2 //侦听队列长度
  10. void process_conn_server(int s);
  11. int main()
  12. {
  13. int serverSocket,clientSocket;
  14. struct sockaddr_in server_addr;//服务器地址结构
  15. struct sockaddr_in client_addr;//客户端地址结构
  16. int err;
  17. pid_t pid;//分叉进程ID
  18. //建立套接字
  19. serverSocket = socket(AF_INET,SOCK_STREAM,0);
  20. if(serverSocket < 0)
  21. {
  22. printf("socket error\n");
  23. return -1;
  24. }
  25. //设置服务器地址
  26. bzero(&server_addr,sizeof(server_addr));
  27. server_addr.sin_family = AF_INET;//协议族
  28. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//本地地址
  29. server_addr.sin_port = htons(PORT);//服务器端口
  30. //帮定地址结构到套接字描述符
  31. err = bind(serverSocket,(struct sockaddr*)&server_addr,sizeof(server_addr));
  32. if(err < 0)
  33. {
  34. printf("bind error\n");
  35. return -1;
  36. }
  37. //设置侦听
  38. err = listen(serverSocket,BACKLOG);
  39. if(err < 0)
  40. {
  41. printf("listen error\n");
  42. return -2;
  43. }
  44. //主循环过程
  45. for(;;)
  46. {
  47. int addrlen = sizeof(struct sockaddr);
  48. clientSocket = accept(serverSocket,(struct sockaddr*)&client_addr,&addrlen);
  49. //接收客户端连接
  50. if(clientSocket < 0)
  51. {
  52. //printf("accept error\n");
  53. continue;
  54. }
  55. printf("客户端连接成功\n");
  56. //建立一个新的连接的进程处理到来的连接
  57. pid = fork();//分叉进程
  58. if(pid == 0)
  59. {
  60. //子进程
  61. close(serverSocket);
  62. process_conn_server(clientSocket);//处理连接
  63. }
  64. else
  65. close(serverSocket);//在父进程中关闭客户端的连接
  66. }
  67. }
  68. void process_conn_server(int s)
  69. {
  70. ssize_t size =0;
  71. char buffer[1024];
  72. memset(buffer,0,1024);
  73. for(;;)
  74. {
  75. size = read(s,buffer,1024);
  76. if(size == 0)
  77. {
  78. printf("size = %d\n",size);
  79. return;
  80. }
  81. sprintf(buffer,"%d bytes altogether\n",size);
  82. write(s,buffer,strlen(buffer)+1);//发送给客户端
  83. }
  84. }
客户端代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <unistd.h>
  7. #include <linux/in.h>
  8. #define PORT 8888 //prot
  9. void process_conn_client(int s);
  10. int main()
  11. {
  12. int s;//s为socket
  13. struct sockaddr_in server_addr;//服务器地址
  14. int err;
  15. s = socket(AF_INET,SOCK_STREAM,0);//建立流式套接字
  16. if(s<0)
  17. {
  18. printf("socket error\n");
  19. return -1;
  20. }
  21. //设置服务器地址
  22. bzero(&server_addr,sizeof(server_addr));
  23. server_addr.sin_family = AF_INET;//协议族
  24. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//本地地址
  25. server_addr.sin_port = htons(PORT);
  26. //将字符串类型的ip地址转为整型
  27. inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr);
  28. //连接服务器
  29. connect(s,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));
  30. process_conn_client(s);//客户端处理过程
  31. close(s);//关闭连接
  32. }
  33. void process_conn_client(int s)
  34. {
  35. ssize_t size = 0;
  36. char buffer[1024];
  37. memset(buffer,0,1024);
  38. for(;;)
  39. {
  40. //从标准输入中读取数据,放到缓冲区中
  41. size = read(0,buffer,1024);
  42. if(size>0)
  43. {
  44. //读到数据
  45. write(s,buffer,size);//发送给服务器
  46. size = read(s,buffer,1024);//从服务器中读取
  47. write(1,buffer,size);//写到标准输出中
  48. }
  49. }
  50. }
执行结果:



send()/recv()函数的代码

服务器代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <unistd.h>
  7. #include <linux/in.h>
  8. #include <signal.h>
  9. void sig_int(int signo);//信号SIGINT处理函数
  10. void sig_pipe(int signo);//信号SIGPIPE处理函数
  11. void process_conn_server(int s);
  12. #define PORT 8888
  13. #define BACKLOG 2
  14. int main()
  15. {
  16. int ss=0,sc=0;
  17. struct sockaddr_in server_addr;//服务器地址结构
  18. struct sockaddr_in client_addr;//客户端地址结构
  19. int err;
  20. pid_t pid;
  21. signal(SIGINT,sig_int);//注册SIGINT信号,通常由CRTL+C终止进程产生的信号
  22. signal(SIGPIPE,sig_pipe);//注册SIGPIPE信号,当正在写入套接字时,读取端关闭时会产生SIGPIPE信号
  23. //建立流式套接字
  24. ss = socket(AF_INET,SOCK_STREAM,0);
  25. if(ss<0)
  26. {
  27. printf("socket error\n");
  28. return -1;
  29. }
  30. //设置服务器地址
  31. bzero(&server_addr,sizeof(server_addr));
  32. server_addr.sin_family = AF_INET;//协议族
  33. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//本地地址
  34. server_addr.sin_port = htons(PORT);//服务器端口
  35. //帮定地址到套接字
  36. err = bind(ss,(struct sockaddr*)&server_addr,sizeof(server_addr));
  37. if(err<0)
  38. {
  39. printf("bind error\n");
  40. return -2;
  41. }
  42. //监听
  43. err = listen(ss,BACKLOG);
  44. if(err<0)
  45. {
  46. printf("listrn error\n");
  47. return -3;
  48. }
  49. printf("服务器已启动:ss=%d\n",ss);
  50. //主循环
  51. for(;;)
  52. {
  53. int addrlen = sizeof(struct sockaddr);
  54. //接收客户端连接
  55. sc = accept(ss,(struct sockaddr*)&client_addr,&addrlen);
  56. if(sc<0)
  57. {
  58. //printf("=====\n");
  59. continue;
  60. }
  61. printf("客户端连接成功\n");
  62. //建立新进程处理到来的请求
  63. pid = fork();
  64. if(pid == 0)
  65. {
  66. //子进程
  67. close(ss);
  68. process_conn_server(sc);//处理连接
  69. }
  70. else
  71. {
  72. //父进程
  73. close(sc);
  74. }
  75. }
  76. }
  77. void process_conn_server(int s)
  78. {
  79. ssize_t size =0;
  80. char buffer[1024];
  81. memset(buffer,0,1024);
  82. for(;;)
  83. {
  84. //从套接字中读取数据到缓冲区
  85. size = recv(s,buffer,1024,0);
  86. if(size == 0)
  87. {
  88. printf("size = %d\n",size);
  89. return;
  90. }
  91. sprintf(buffer,"%d bytes altogether\n",size);
  92. send(s,buffer,strlen(buffer)+1,0);//发送给客户端
  93. }
  94. }
  95. void sig_int(int signo)
  96. {
  97. printf("Catch a SIGINT signal\n");
  98. _exit(0);
  99. }
  100. void sig_pipe(int signo)
  101. {
  102. printf("Catch a SIGPIPE signal\n");
  103. }
客户端代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <unistd.h>
  7. #include <linux/in.h>
  8. #include <signal.h>
  9. #include <errno.h>
  10. void sig_int(int signo);//信号SIGINT处理函数
  11. void sig_pipe(int signo);//信号SIGPIPE处理函数
  12. void sig_process_client(int signo);
  13. void process_conn_client(int s);
  14. #define PORT 8888
  15. static int s;
  16. int main()
  17. {
  18. struct sockaddr_in server_addr;//服务器地址结构
  19. int err;
  20. signal(SIGINT,sig_int);
  21. signal(SIGPIPE,sig_pipe);
  22. //建立套接字
  23. s = socket(AF_INET,SOCK_STREAM,0);
  24. if(s<0)
  25. {
  26. printf("socket error\n");
  27. return -1;
  28. }
  29. //设置服务器地址
  30. bzero(&server_addr,sizeof(server_addr));
  31. server_addr.sin_family = AF_INET;
  32. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  33. server_addr.sin_port = htons(PORT);
  34. inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr);
  35. //inet_pton(AF_INET,"127.0.0.1",&server_addr,&server_addr.sin_addr);//这里传入三个参数,linux下居然没有报错,找了几天才找出错误
  36. err = connect(s,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));
  37. if(err<0)
  38. {
  39. printf("connect error:errno=%d\n",errno);
  40. return -2;
  41. }
  42. process_conn_client(s);//客户端处理连接函数
  43. close(s);
  44. }
  45. void process_conn_client(int s)
  46. {
  47. ssize_t size = 0;
  48. char buffer[1024];
  49. memset(buffer,0,1024);
  50. printf("客户端已启动\n");
  51. for(;;)
  52. {
  53. size = read(0,buffer,1024);//从标准输入读取数据
  54. if(size>0)
  55. {
  56. send(s,buffer,size,0);//发送给客户端
  57. size = recv(s,buffer,1024,0);//从服务器端读取数据
  58. write(1,buffer,size);//写到标准输出中
  59. }
  60. }
  61. }
  62. void sig_int(int signo)
  63. {
  64. printf("Catch a SIGINT signal\n");
  65. close(s);
  66. _exit(0);
  67. }
  68. void sig_pipe(int signo)
  69. {
  70. printf("Catch a SIGPIPE signal\n");
  71. }
  72. void sig_process_client(int signo)
  73. {
  74. printf("Catch a exit signal\n");
  75. close(s);
  76. _exit(0);
  77. }
最终结果:



readv()/wirtev()函数


下面代码时利用上述两个函数将数据写入向量中,并从向量中获取数据。
服务器代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <unistd.h>
  7. #include <linux/in.h>
  8. #include <signal.h>
  9. #include <sys/uio.h>
  10. static struct iovec *vs=NULL,*vc=NULL;
  11. void sig_int(int signo);//信号SIGINT处理函数
  12. void sig_pipe(int signo);//信号SIGPIPE处理函数
  13. void process_conn_server(int s);
  14. #define PORT 8888
  15. #define BACKLOG 2
  16. int main()
  17. {
  18. int ss=0,sc=0;
  19. struct sockaddr_in server_addr;//服务器地址结构
  20. struct sockaddr_in client_addr;//客户端地址结构
  21. int err;
  22. pid_t pid;
  23. signal(SIGINT,sig_int);//注册SIGINT信号,通常由CRTL+C终止进程产生的信号
  24. signal(SIGPIPE,sig_pipe);//注册SIGPIPE信号,当正在写入套接字时,读取端关闭时会产生SIGPIPE信号
  25. //建立流式套接字
  26. ss = socket(AF_INET,SOCK_STREAM,0);
  27. if(ss<0)
  28. {
  29. printf("socket error\n");
  30. return -1;
  31. }
  32. //设置服务器地址
  33. bzero(&server_addr,sizeof(server_addr));
  34. server_addr.sin_family = AF_INET;//协议族
  35. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//本地地址
  36. server_addr.sin_port = htons(PORT);//服务器端口
  37. //帮定地址到套接字
  38. err = bind(ss,(struct sockaddr*)&server_addr,sizeof(server_addr));
  39. if(err<0)
  40. {
  41. printf("bind error\n");
  42. return -2;
  43. }
  44. //监听
  45. err = listen(ss,BACKLOG);
  46. if(err<0)
  47. {
  48. printf("listrn error\n");
  49. return -3;
  50. }
  51. printf("服务器已启动:ss=%d\n",ss);
  52. //主循环
  53. for(;;)
  54. {
  55. int addrlen = sizeof(struct sockaddr);
  56. //接收客户端连接
  57. sc = accept(ss,(struct sockaddr*)&client_addr,&addrlen);
  58. if(sc<0)
  59. {
  60. //printf("=====\n");
  61. continue;
  62. }
  63. printf("客户端连接成功\n");
  64. //建立新进程处理到来的请求
  65. pid = fork();
  66. if(pid == 0)
  67. {
  68. //子进程
  69. close(ss);
  70. process_conn_server(sc);//处理连接
  71. }
  72. else
  73. {
  74. //父进程
  75. close(sc);
  76. }
  77. }
  78. }
  79. void process_conn_server(int s)
  80. {
  81. ssize_t size =0;
  82. char buffer[30];
  83. memset(buffer,0,30);
  84. //申请3个向量
  85. struct iovec* v=(struct iovec*)malloc(3*sizeof(struct iovec));
  86. if(!v)
  87. {
  88. printf("Not enough memory\n");
  89. return;
  90. }
  91. vs=v;//挂载全局变量,便于释放管理
  92. //每个向量10个字节
  93. v[0].iov_base = buffer;
  94. v[1].iov_base = buffer+10;
  95. v[2].iov_base = buffer+20;
  96. v[0].iov_len = v[0].iov_len = v[0].iov_len = 10;
  97. //循环过程
  98. for(;;)
  99. {
  100. memset(buffer,0,30);
  101. //从套接字中读取数据放到向量缓冲区中
  102. size = readv(s,v,3);
  103. if(size == 0)
  104. return;
  105. //这里可以输出接收到的字符串
  106. int i=0;
  107. printf("客户端发来消息:\n");
  108. for(i=0;i<3;i++)
  109. {
  110. if(v[i].iov_len > 0)
  111. write(1,v[i].iov_base,v[i].iov_len);//写到标准输出
  112. }
  113. printf("\n");
  114. memset(buffer,0,30);
  115. //构建响应字符,为接收到客户端字节的数量,分别放到3个缓冲区中
  116. sprintf(v[0].iov_base,"%d",size);
  117. sprintf(v[1].iov_base,"bytes alt");
  118. sprintf(v[2].iov_base,"ogether\n");
  119. v[0].iov_len = strlen(v[0].iov_base);
  120. v[1].iov_len = strlen(v[1].iov_base);
  121. v[2].iov_len = strlen(v[2].iov_base);
  122. //发送给客户端
  123. writev(s,v,3);
  124. }
  125. }
  126. void sig_int(int signo)
  127. {
  128. printf("Catch a SIGINT signal\n");
  129. free(vs);
  130. free(vc);
  131. _exit(0);
  132. }
  133. void sig_pipe(int signo)
  134. {
  135. printf("Catch a SIGPIPE signal\n");
  136. free(vs);
  137. free(vc);
  138. _exit(0);
  139. }
客户端代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <unistd.h>
  7. #include <linux/in.h>
  8. #include <signal.h>
  9. #include <errno.h>
  10. void sig_int(int signo);//信号SIGINT处理函数
  11. void sig_pipe(int signo);//信号SIGPIPE处理函数
  12. void sig_process_client(int signo);
  13. void process_conn_client(int s);
  14. #define PORT 8888
  15. static int s;
  16. static struct iovec *vs=NULL,*vc=NULL;
  17. int main()
  18. {
  19. struct sockaddr_in server_addr;//服务器地址结构
  20. int err;
  21. signal(SIGINT,sig_int);
  22. signal(SIGPIPE,sig_pipe);
  23. //建立套接字
  24. s = socket(AF_INET,SOCK_STREAM,0);
  25. if(s<0)
  26. {
  27. printf("socket error\n");
  28. return -1;
  29. }
  30. //设置服务器地址
  31. bzero(&server_addr,sizeof(server_addr));
  32. server_addr.sin_family = AF_INET;
  33. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  34. server_addr.sin_port = htons(PORT);
  35. inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr);
  36. err = connect(s,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));
  37. if(err<0)
  38. {
  39. printf("connect error:errno=%d\n",errno);
  40. return -2;
  41. }
  42. process_conn_client(s);//客户端处理连接函数
  43. close(s);
  44. }
  45. void process_conn_client(int s)
  46. {
  47. ssize_t size = 0;
  48. char buffer[30];
  49. memset(buffer,0,30);
  50. printf("客户端已启动\n");
  51. struct iovec *v=(struct iovec*)malloc(3*sizeof(struct iovec));
  52. if(!v)
  53. {
  54. printf("Not enough memory\n");
  55. return;
  56. }
  57. vc=v;//挂载全局变量,便于释放
  58. //每个向量10个字节的空间
  59. v[0].iov_base = buffer;
  60. v[1].iov_base = buffer+10;
  61. v[2].iov_base = buffer+20;
  62. v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;//初始化长度
  63. int i = 0;
  64. for(;;)
  65. {
  66. //从标准输入中读取数据放到缓冲区buffer中
  67. size = read(0,v[0].iov_base,10);
  68. if(size>0)
  69. {
  70. v[0].iov_len=size;
  71. writev(s,v,1);//发送给服务器,最后1表示1个缓冲区
  72. v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;
  73. size = readv(s,v,3);//从服务器读取数据
  74. for(i=0;i<3;i++)
  75. {
  76. if(v[i].iov_len > 0)
  77. write(1,v[i].iov_base,v[i].iov_len);//写到标准输出
  78. }
  79. }
  80. }
  81. }
  82. void sig_int(int signo)
  83. {
  84. printf("Catch a SIGINT signal\n");
  85. close(s);
  86. free(vs);
  87. free(vc);
  88. _exit(0);
  89. }
  90. void sig_pipe(int signo)
  91. {
  92. free(vs);
  93. free(vc);
  94. printf("Catch a SIGPIPE signal\n");
  95. _exit(0);
  96. }
  97. void sig_process_client(int signo)
  98. {
  99. printf("Catch a exit signal\n");
  100. close(s);
  101. _exit(0);
  102. }
最终运行结果:




recvmsg()/sendmsg()函数
与readv()和writev()的服务器处理过程相似,使用消息函数进行IO的服务器处理过程同样适用3个10字节大小的向量缓冲区来保存数据。但是并不是直接对这些向量进行操作,而是将向量挂在消息结构msghdr的msg_iov成员变量上进行操作,并将向量的存储空间长度设为30。在服务器端调用函数recvmsg()从套接字s中接收数据到msg中,将接收到的消息进行处理后,调用sendmsg()函数将相应数据通过套接字s发出。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值