套接字(socket)编程简单实现server-client聊天程序

来源:互联网 发布:少儿英语软件推荐 编辑:程序博客网 时间:2024/05/22 12:24

1、socket

      在TCP/IP协议中,一个IP地址标识网络通讯中唯一一台主机,而一个IP地址+一个TCP(或UDP)端口号就可以标识网络通讯中的一个进程,此时的IP地址+端口号即称为socket。
      内存中的多字节数据相对于内存地址有大小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大小端之分,网络数据流同样也有大小端之分:先发出的数据是低地址,后发出的数据是搞地质,TCP/IP协议规定网络数据流采用大端字节序,即低地址高字节。
      1)计算机分为大端机和小端机,那么如何使同样的C代码在大端机和小端机上都能正常运行呢?库函数一节为我们提供了转换的接口:

include<arpa/inet.h>unit32_t htonl(unit32_t hostlong);//32位的长整数从主机字节序转换为网络字节序unit16_t htons(unit16_t hostshort);//16位的短整数从主机字节序转换为网络字节序unit32_t ntohl(unit32_t netlong);//32位的长整数从网络字节序转换为主机字节序unit16_t ntohs(unit16_t netshort);//16位的短整数从网络字节序转换为主机字节序

      2)由于网络传输是二进制比特流传输,所以必须将我们常用的十进制的IP地址与网络字节序的二进制形式的IP源码互相转换才可以将数据传输到准确的地址,下面是地址转换函数介绍:

int inet_aton(const char* cp, struct in_addr *inp);//将字符串cp的十进制转换为网络字节序的二进制形式后存储到inp中char* inet_ntoa(struct in_addr *in);//将网络字节序的二进制形式转换为十进制的字符串形式,返回字符串的首地址

2、socket地址的数据类型及相关函数

      1)结构体
            IPV4套接字地址结构体:

struct sockaddr_in{unit8_t sin_len;sa_famliy_t sin_famliy;//协议家族in_port_t sin_port;//端口号struct in_addr  sin_addr;//IP地址char sin_zero[8];};

      通用套接字地址结构体:

struct sockaddr{unit8_t sa_len;sa_famliy sa_famlity;char sa_data[14];};

      2)相关函数
      socket:

这里写图片描述

      bind:
这里写图片描述

      listen:
这里写图片描述

      accept与connect:
这里写图片描述

      send和recv:
这里写图片描述

      close:
这里写图片描述

3、下面通过简单的客户端/服务器程序实例来学习socket API。

      server端即服务器端:服务器由于不知道客户何时回请求建立连接,所以必须绑定端口之后进行监听;
      client端即客户端:只需向服务器端发送连接请求(connect);
      客户端主动发起请求连接,服务器接受连接请求,完成“三次握手”;服务器与客户端都可以发起断开连接请求,完成”四次挥手“的过程。
      基本框架图(此图为摘录):

这里写图片描述

代码如下:
server.c:

#include<stdio.h>#include<stdlib.h>#include<sys/socket.h>#include<netinet/in.h>#include<unistd.h>#include<string.h>#include<sys/types.h>#define _PORT_ 9999#define _BACKLOG_ 10int main(){    int sock = socket(AF_INET, SOCK_STREAM, 0);    if(sock < 0){        perror("socket");        exit(1);    }    int opt = 1;    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));    struct sockaddr_in server_socket;    struct sockaddr_in client_socket;                                               bzero(&server_socket, sizeof(server_socket));    server_socket.sin_family = AF_INET;    server_socket.sin_addr.s_addr = htonl(INADDR_ANY);    server_socket.sin_port = htons(_PORT_);    if(bind(sock, (struct sockaddr*)&server_socket, sizeof(struct sockaddr_in)) < 0)    {        perror("bind");        close(sock);        exit(2);    }    if(listen(sock, _BACKLOG_) < 0)    {        perror("listen");        close(sock);        exit(3);    }    printf("bind and listen success, wait accept..\n");    while(1)    {        socklen_t len = 0;                                                              int client_sock = accept(sock, (struct sockaddr*)&client_socket, &len);        if(client_sock < 0)        {            perror("accept");            close(sock);            exit(4);        }        char buf_ip[INET_ADDRSTRLEN];        memset(buf_ip, '\0', sizeof(buf_ip));        inet_ntop(AF_INET,&client_socket.sin_addr, buf_ip, sizeof(buf_ip));        printf("get connect, ip is : %s port is : %d\n",buf_ip, ntohs(client_socket.sin_port));        while(1)        {            char buf[1024];            memset(buf, '\0',sizeof(buf));            read(client_sock, buf, sizeof(buf));            printf("client#:%s\n",buf);            printf("server#:");            memset(buf, '\0', sizeof(buf));            fgets(buf, sizeof(buf), stdin);            buf[strlen(buf)-1] = '\0';            write(client_sock, buf, strlen(buf)+1);            printf("please wait...\n");                                                 }    }    close(sock);    return 0;}

client.c:

#include<stdio.h>                                                               #include<unistd.h>#include<sys/socket.h>#include<sys/types.h>#include<string.h>#include<netinet/in.h>#include<arpa/inet.h>#define SERVER_PORT 9999#define SERVER_IP "192.168.43.121"int main(int argc, char *argv[]){    if(argc != 2)    {   printf("Usage: client IP \n");        return 1;    }    char *str = argv[1];    char buf[1024];    memset(buf, '\0', sizeof(buf));    struct sockaddr_in server_sock;    int sock = socket(AF_INET, SOCK_STREAM, 0);    bzero(&server_sock, sizeof(server_sock));    server_sock.sin_family = AF_INET;    inet_pton(AF_INET, SERVER_IP, &server_sock.sin_addr);    server_sock.sin_port = htons(SERVER_PORT);    int ret = connect(sock, (struct sockaddr*)&server_sock, sizeof(server_sock));    if(ret < 0)    {        printf("perror");        return 1;    }    printf("connect success....\n");    while(1)    {        printf("client#:");        fgets(buf, sizeof(buf), stdin);        buf[strlen(buf)-1] = '\0';        write(sock, buf, sizeof(buf));        if(strncasecmp(buf, "quit", 4) == 0)        {            perror("perror");            break;        }        printf("please wait...\n");        read(sock, buf, sizeof(buf));        printf("server$: %s\n",buf);                                                }    close(sock);    return 0;}

4、测试结果

      打开一个terminal运行服务器端server,再打开另外一个terminal运行客户端client,并加上通过ifconfig查出的IP地址即可实现服务器端与客户端的连接。

这里写图片描述

原创粉丝点击