Linux下TCP Socket编程

来源:互联网 发布:java 双亲委派 编辑:程序博客网 时间:2024/04/30 12:19

1.TCP网络编程架构

    TCP网络编程有两种模式,一种是服务器模式,另一种是客户端模式。服务器模式是通过建立一个服务监听客户端连接,当服务器收到客户端连接请求后,对请求进行处理;客户端模式是通过绑定服务器IP地址和端口,向服务器发送连接请求,并对服务器响应做出相应的处理。下图为TCP网络编程两种模式的架构图。

1  socket()介绍
  1. int socket(int domain,int type,int protocol)
domain 是用来设置网络通信域的,也就是选择你所采用的协议族。如,AF_INET代表ipv4,AF_INET6代表ipv6.
type 是用来设置套接字通信类型的。常用的类型有SOCK_STREAM(流式套接字)支持TCP连接,提供可靠的、序列化的、双向的字节流;SOCK_DGRAM(数据包套接字),支持UPD连接,无连接不可靠。
protocol 使用来指定type类型中的某个类型。通常某个协议只有一个特定的类型,这样protocol设置为0;但是,也有默写协议不止一个特定类型,使用这个协议时,就需要指明所使用协议的具体特定类型。
socket 函数通过以上三个参数最终生成一个套接字文件描述符。
  1. int sockfd = socket(AF_INET,SOCK_STREAM,0);
2 bind()介绍
  1. int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);
首先介绍一下结构体sockaddr
  1. struct sockaddr{
  2. sa_family_t sa_family;//协议族
  3. char sa_data[14];//协议族数据
  4. }
其中,sa_family_t类型其实就是unsigned short类型;
接下来介绍bind函数中参数:
sockfd 为套接字文件描述符;
myaddr 为指向套接字地址结构的指针。在进行sockfd绑定的时候,需要将IP地址,端口、协议类型等信息进行绑定。而sockaddr结构体不方便设置,所以在以太网中,一般采用结构体struct sockaddr_in进行设置:
  1. struct sockaddr_in{
  2. u8 sin_len; //结构体长度
  3. u8 sin_family; //采用的协议族
  4. u16 sin_port; //端口号,网络字节序
  5. struct in_addr sin_addr; //IP地址32bits
  6. char sin_zero[8]; //未用
  7. }
结构体struct sockaddr 和结构体 struct sockaddr_in 大小相同,两者可以相互转化。可以说,struct sockaddr_instruct sockaddr的细化。addrlen 是myaddr的长度,addrlen = sizeof(struct sockaddr);
3 listen()介绍
  1. int listen(int sockfd,int backlog);
在接受一个连接之前,需要使用listen来监听端口,backlog表示在accept()函数处理之前在等待队列中的客户端长度。
4 accept()介绍
当一个客户端请求到达服务器所监听的端口后,服务器会将此时的客户端请求加入到客户端等待队列中,直到使用accept()处理请求。accept()成功执行后,会返回一个客户端的套接字文件描述符,客户端的信息可以通过这个描述符来获得。
  1. int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
其中,根据addr可以获得IP、端口、协议类型等信息。 这里需要注意的是,addlen是一个指针,accept将其传给TCP/IP协议栈。
 5 connect()介绍
客户端在建立套接字后,不需要绑定IP,端口等信息。客户端通过connect()函数连接服务器,connect()中指定了服务器IP地址、目的端口等信息。
  1. int connect(int sockfd,struct sockaddr *, int addrlen);
6 write()介绍
当服务器收到一个客户端连接后,通过套接字描述符来进行数据写入。
  1. int size = write(s,data,1024);
将data中的数据全部写入s中,返回值为成功写入的数据长度。
7 客户端服务器实现代码:
服务器代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <arpa/inet.h>
  7. #include <unistd.h>
  8. #define PORT 8888/*侦听端口地址*/
  9. #define BACKLOG 2/*侦听队列长度*/
  10. int main(int argc, char *argv[])
  11. {
  12. int ss,sc;/*ss为服务器的socket描述符,sc为客户端的socket描述符*/
  13. struct sockaddr_in server_addr;/*服务器地址结构*/
  14. struct sockaddr_in client_addr;/*客户端地址结构*/
  15. int err;/*返回值*/
  16. pid_t pid;/*分叉的进行ID*/
  17. /*建立一个流式套接字*/
  18. ss = socket(AF_INET, SOCK_STREAM, 0);
  19. if(ss < 0){/*出错*/
  20. printf("socket error\n");
  21. return -1;
  22. }
  23. /*设置服务器地址*/
  24. bzero(&server_addr, sizeof(server_addr));/*清零*/
  25. server_addr.sin_family = AF_INET;/*协议族*/
  26. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);/*本地地址*/
  27. server_addr.sin_port = htons(PORT);/*服务器端口*/
  28. /*绑定地址结构到套接字描述符*/
  29. err = bind(ss, (struct sockaddr*)&server_addr, sizeof(server_addr));
  30. if(err < 0){/*出错*/
  31. printf("bind error\n");
  32. return -1;
  33. }
  34. /*设置侦听*/
  35. err = listen(ss, BACKLOG);
  36. if(err < 0){/*出错*/
  37. printf("listen error\n");
  38. return -1;
  39. }
  40. /*主循环过程*/
  41. for(;;){
  42. socklen_t addrlen = sizeof(struct sockaddr);
  43. sc = accept(ss, (struct sockaddr*)&client_addr, &addrlen);
  44. /*接收客户端连接*/
  45. if(sc < 0){/*出错*/
  46. continue;/*结束本次循环*/
  47. }
  48. /*建立一个新的进程处理到来的连接*/
  49. pid = fork();/*分叉进程*/
  50. if( pid == 0 ){/*子进程中*/
  51. process_conn_server(sc);/*处理连接*/
  52. close(ss);/*在子进程中关闭服务器的侦听*/
  53. }else{
  54. close(sc);/*在父进程中关闭客户端的连接*/
  55. }
  56. }
  57. }
客户端代码:
  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 <arpa/inet.h>
  8. #define PORT 8888/*侦听端口地址*/
  9. int main(int argc, char *argv[])
  10. {
  11. int s;/*s为socket描述符*/
  12. struct sockaddr_in server_addr;/*服务器地址结构*/
  13. s = socket(AF_INET, SOCK_STREAM, 0); /*建立一个流式套接字 */
  14. if(s < 0){/*出错*/
  15. printf("socket error\n");
  16. return -1;
  17. }
  18. /*设置服务器地址*/
  19. bzero(&server_addr, sizeof(server_addr));/*清零*/
  20. server_addr.sin_family = AF_INET;/*协议族*/
  21. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);/*本地地址*/
  22. server_addr.sin_port = htons(PORT);/*服务器端口*/
  23. /*将用户输入的字符串类型的IP地址转为整型*/
  24. inet_pton(AF_INET, argv[1], &server_addr.sin_addr);
  25. /*连接服务器*/
  26. connect(s, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
  27. process_conn_client(s);/*客户端处理过程*/
  28. close(s);/*关闭连接*/
  29. return 0;
  30. }
完整代码见http://download.csdn.net/detail/qq_14976351/9630793
0 0