一、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*/
#include<arpa/inet.h>

int 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<sys/types.h>
#include<sys/socket.h>

/*创建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<unistd.h>
int close(int fd);

三、使用TCP协议的socket编程的流程如下图

socket编程总结_编程

根据上面流程编写client.c

#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
#include<errno.h>  
#include<sys/types.h>  
#include<sys/socket.h>  
#include<netinet/in.h>  
  
#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 <ipaddress>\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<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
#include<errno.h>  
#include<sys/types.h>  
#include<sys/socket.h>  
#include<netinet/in.h>  
#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程序

socket编程总结_socket_02

2、运行client程序

socket编程总结_socket_03

3、server接收成功

socket编程总结_编程_04