网络程序设计——1.TCP、UDP网络编程

运行环境:

VMware搭载的Linux虚拟机

Linux版本:Ubantu14.04LTS

 

一、原理

1、TCP/IP协议存在于OS中,网络服务通过OS提供。

2、应用程序要和操作系统交互,才能使用TCP/IP提供的网络通信功能。

3、交互的接口:即应用程序接口(API)。

4、从网络的观点看:TCP/IP和应用程序之间的接口。

二、流程

以TCP为例:

三、代码及结果

1.TCP编程

//tcp_server.c
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <time.h>
#include <memory.h>
#include <signal.h>

void print(struct sockaddr_in *addr){
    int port2 = ntohs(addr->sin_port);
    char ip[16];
    memset(ip, 0, sizeof(ip));
    inet_ntop(AF_INET, &addr->sin_addr.s_addr, ip, sizeof(ip));
    printf("server: (client address: %s(%d) connected)\n", ip, port2);
}

void do_service(int cfd){
    long t = time(0);
    char* s = ctime(&t);
    size_t size = strlen(s) * sizeof(char);
    if( send(cfd, s, size,MSG_DONTWAIT) != size)
        perror("write error");
}

int fd;
void sig_handler(int sig){
    if(sig == SIGINT){
        close(fd);
        exit(1);
    }
}

int main(void){
//    if(signal(SIGINT, sig_handler) == SIG_ERR){
//        perror("signal sigint error");
//        exit(1);
//    }

    //第一步 创建socket
    //AF_INET: IPV4
    //SOCK_STREAM: tcp
    //0: 默认协议
    if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        perror("socket create error");
    printf("server: socket created\n");

    //这两行解决 Bind error: Address already in use
    //可以使绑定的ip关闭后立刻重新使用
    int on = 1;
    int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

    //第二步 调用bind 将socket与地址端口绑定
    struct sockaddr_in  sock_addr;
    memset(&sock_addr, 0, sizeof(sock_addr));
    sock_addr.sin_family = AF_INET;
    int port = 12345;
    sock_addr.sin_port = htons(port); //主机字节序转为网络字节序
    sock_addr.sin_addr.s_addr = INADDR_ANY;
    if(bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0)
        perror("bind error");
    printf("server: bind OK\n");

    //第三步 调用listen启动监听(指定port监听)
    //通知系统去接受来自客户端的连接请求
    //(将接受到的客户端连接放置到长度为10的队列中)
    if(listen(fd, 10) < 0)
        perror("listen error");
    printf("server: listen OK\n");

    //第四步 调用accept函数从队列中获得一个客户端的请求连接
    //并返回一个客户端的socket文件描述符
    //如果没有客户端连接请求, 到这里会阻塞
    //第二个参数用来获得客户端的地址结构
    int client_fd;
    struct sockaddr new_addr;
    int len = sizeof(new_addr);
    if( (client_fd = accept(fd, &new_addr, &len)) < 0 )
        perror("accept error");
    printf("server: accept  OK\n");

    //应答  (读客户端数据, 写数据给客户端)
    print((struct sockaddr_in*)&new_addr);
    do_service(client_fd);

    //关闭socket文件
    close(fd);
    printf("server: close OK\n");
    return 0;
}
//tcp_client.c
#include <netdb.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>

const int port = 12345;
const char* ipaddr = "127.0.0.1";//测试地址,也即"localhost"

int main(void){

    int fd;
    if((fd = socket(AF_INET,SOCK_STREAM,0)) < 0)
        perror("socket create error");
    printf("client: socket created\n");
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;

    //主机字节序改网络字节序
    //host to network
    serveraddr.sin_port = htons(port);
    //pointer to network
    inet_pton(AF_INET, ipaddr, &serveraddr.sin_addr.s_addr);
    //调用connect指定服务器的ip
    if(connect(fd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
        perror("connect error");
    printf("client: connect OK\n");

    char buffer[1024];
    memset(buffer, 0, sizeof(buffer));
    size_t size;
    if((size = recv(fd, buffer, sizeof(buffer), 0)) < 0)
        perror("read error");
    printf("client read content: %s", buffer);

    close(fd);
    return 0;
}

运行结果

编译并运行服务器端程序:

打开测试网页127.0.0.1:

    可以看出从服务器端获取了当前时间并显示

编译客户端程序,并进行连接

   

客户端成功读取并显示服务器端程序

2.UDP编程

//udp_server.c
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <time.h>
#include <memory.h>
#include <signal.h>

void print(struct sockaddr_in *addr){
    int port2 = ntohs(addr->sin_port);
    char ip[16];
    memset(ip, 0, sizeof(ip));
    inet_ntop(AF_INET, &addr->sin_addr.s_addr, ip, sizeof(ip));
    printf("server: (client address: %s(%d) connected)\n", ip, port2);
}


int fd;
void sig_handler(int sig){
    if(sig == SIGINT){
        close(fd);
        exit(1);
    }
}

int main(void){
//    if(signal(SIGINT, sig_handler) == SIG_ERR){
//        perror("signal sigint error");
//        exit(1);
//    }

    //第一步 创建socket
    //AF_INET: IPV4
    //SOCK_STREAM: tcp
    //0: 默认协议
    if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        perror("socket create error");
    printf("server: socket created\n");

    //这两行解决 Bind error: Address already in use
    //可以使绑定的ip关闭后立刻重新使用
    int on = 1;
    int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

    //第二步 调用bind 将socket与地址端口绑定
    struct sockaddr_in  sock_addr;
    memset(&sock_addr, 0, sizeof(sock_addr));
    sock_addr.sin_family = AF_INET;
    int port = 12345;
    sock_addr.sin_port = htons(port); //主机字节序转为网络字节序
    sock_addr.sin_addr.s_addr = INADDR_ANY;
    if(bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0)
        perror("bind error");
    printf("server: bind OK\n");

    int client_len,len;
    char buf[1024];
	char ipstr[INET_ADDRSTRLEN]; //16 Bytes
    struct sockaddr_in clientaddr;
    int i;
//    while(1){
    client_len = sizeof(clientaddr);
    len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&clientaddr, &client_len);
    print(&clientaddr);
    for(i = 0; i < len; i++)
    {
        buf[i] = toupper(buf[i]);
    }
    buf[len] = '\0';
    sendto(fd,buf,sizeof(buf),0,(struct sockaddr *)&clientaddr, sizeof(clientaddr));

    //关闭socket文件
    close(fd);
    printf("server: close OK\n");
    return 0;
}
//ddp_client.c
#include <netdb.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>

const int port = 12345;
const char* ipaddr = "127.0.0.1";

int main(int argc, char *argv[]){

    int fd;
    if((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
        perror("socket create error");
    printf("client: socket created\n");
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;

    //主机字节序改网络字节序
    //host to network
    serveraddr.sin_port = htons(port);
    //pointer to network
    inet_pton(AF_INET, ipaddr, &serveraddr.sin_addr.s_addr);
    //调用connect指定服务器的ip
//    if(connect(fd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
//        perror("connect error");
//    printf("client: connect OK\n");

    char buffer[1024];
    memset(buffer, 0, sizeof(buffer));
    size_t size;
    int addr_len = sizeof(serveraddr);

    sendto(fd, argv[1], strlen(argv[1]), 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    if((size = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&serveraddr, &addr_len)) < 0)
        perror("read error");
    printf("client read content: %s", buffer);

    close(fd);
    return 0;
}

运行结果

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值