一、socket地址api。socket最开始的含义是一个IP地址和端口对。他唯一地表示了使用TCP通信的一端。(主要讨论ipv4)
1、ipv4socket地址:
struct sockaddr_in { sa_family_t sin_family; /*地址族:AF_INET*/ u_int16 sin_port; /*端口号,要用网络字节序表示*/ struct in_addr sin_addr; /*ipv4地址结构*/ }; struct in_addr { u_int32_t s_addr; /*ipv4地址,要用网络字节表示*/ };
2、ip地址转换函数
/*字符串转in_addr*/ #includeint inet_aton(const char *strptr,struct in_addr *addrptr); in_addr_t inet_addr(const char *strptr); int inet_pton(int family,const char *strptr,void *addrptr); /*in_addr转字符串*/ char *inet_ntoa(struct in_addr inaddr); const char *inet_ntop(int family,const void *addrptr,char *strptr,size_t len);
其中inet_pton和inet_ntop不仅可以转换ipv4地址,而且可以转换ipv6的地址。
二、socket基础API。创建socket、命名socket、监听、socket、接收连接、发起连接、读写数据、获取地址信息。
#include#include /*创建socket*/ int socket(int domain,int type,int protocol); /*domain表示那个协议,对于TCP/IP协议而言是PF_INET/PT_INET6;type服务类型,TCP使用 SOCK_STREAML(流服务)、UDP使用SOCK_DGRAM(数据报);protocol一般情况都是0 调用成功返回一个socket文件描述符,失败返回-1并设置errno*/ /*绑定或命名socket*/ int bind(int sockfd,const struct sockaddr* my_addr,socklen_t addrlen); /*将my_addr所指的socket地址分配给未命名的sockfd文件描述符,addrlen参数是socket地址长度 调用成功返回0,失败返回-1并设置errno。*/ /*监听socket*/ int listen(int sockfd,int backlog); /*sockfd参数指定被监听的socket;backlog提示内核监听队列的最大长度,典型值是5。 调用成功返回0,失败返回-1并设置errno。*/ /*接受连接*/ int accept(int sockfd,struct sockaddr *addr,socklen_t* addrlen); /*sockfd参数是执行过listen系统调用的监听socket。addr参数用来获取接收连接的远端socket地址 ,该socket地址长度由addrlen参数指出。 调用成功返回一个新的连接socket,该socket唯一地标识了被接收的这个连接,服务器可以通过读写该 socket来与被接受连接对应的客户端通信。失败时返回-1并设置errno*/ /*向服务器发送连接*/ int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addrlen); /*sockfd 参数有socket系统调用返回一个socket。serv_addr参数是服务器监听的socket地址,addlen 参数指定这个地址的长度。 调用成功返回0。一旦成功建立连接,sockfd就唯一地标识了这个连接,客户端就可以通过读写sockfd 来与服务器通信。失败返回-1并设置errno*/ /*从socket上读取数据,向socket上写数据*/ ssize_t recv(int sockfd,void *buf,size_t len,int flags); ssize_t send(int sockfd,const void *buf,size_t len,int flags); /*recv读取sockfd上的数据,buf和len参数分别指定缓冲区的位置和大小,flags参数通常是0 send往sockfd上写入数据,buf和len参数分别指定写缓冲区的位置和大小。*/ /*关闭socket*/ #include int close(int fd);
三、使用TCP协议的socket编程的流程如下图
根据上面流程编写client.c
#include#include #include #include #include #include #include #define MAXLINE 4096 int main(int argc, char** argv) { int sockfd, n,rec_len; char recvline[4096], sendline[4096]; char buf[MAXLINE]; struct sockaddr_in servaddr; if( argc != 2){ printf("usage: ./client \n"); exit(0); } /*创建socket*/ if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8000); /*转换socket地址*/ if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){ printf("inet_pton error for %s\n",argv[1]); exit(0); } /*向服务器发起连接*/ if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){ printf("connect error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("send msg to server: \n"); fgets(sendline, 4096, stdin); /*往socket上写数据*/ if( send(sockfd, sendline, strlen(sendline), 0) < 0) { printf("send msg error: %s(errno: %d)\n", strerror(errno), errno); exit(0); } /*从socket上读数据*/ if((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) { perror("recv error"); exit(1); } buf[rec_len] = '\0'; printf("Received : %s ",buf); /*关闭socket*/ close(sockfd); exit(0); }
server.c
#include#include #include #include #include #include #include #define DEFAULT_PORT 8000 #define MAXLINE 4096 int main(int argc, char** argv) { int socket_fd, connect_fd; struct sockaddr_in servaddr; char buff[4096]; int n; /*创建Socket */ if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){ printf("create socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } /*初始化*/ memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//我认为是任意地址 servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT /*将本地地址绑定到所创建的套接字上*/ if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } /*开始监听是否有客户端连接*/ if( listen(socket_fd, 10) == -1){ printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("======waiting for client's request======\n"); while(1){ /*阻塞直到有客户端连接,接收连接*/ if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){ printf("accept socket error: %s(errno: %d)",strerror(errno),errno); continue; } /*接受客户端传过来的数据*/ n = recv(connect_fd, buff, MAXLINE, 0); /*向客户端发送回应数据*/ if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1) perror("send error"); buff[n] = '\0'; printf("recv msg from client: %s\n", buff); close(connect_fd); } close(socket_fd); }
运行结果:
1、运行server程序
2、运行client程序
3、server接收成功