socket例程

  server.c
--------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define SERVER_PORT 12345
#define BUF_SIZE    4096
#define QUEUE_SIZE 10

int fatal(char *string)
{
    printf("%s\n", string);
    exit(1);
}


int main(int argc, char * argv[])
{
    int s, b, l, fd, sa, bytes, on = 1;
    char buf[BUF_SIZE];
    struct sockaddr_in channel;
   
    memset(&channel, 0, sizeof(channel));
    channel.sin_family = AF_INET;
    channel.sin_addr.s_addr = htonl(INADDR_ANY);
    channel.sin_port = htons(SERVER_PORT);
   
    s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s < 0)
        fatal("socket failed");
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); //(1)

    b = bind(s, (struct sockaddr *)&channel, sizeof(channel));        //(2)
    if (b <0)
        fatal("bind failed");

    l = listen(s, QUEUE_SIZE);        //(3)
    if (l < 0)
        fatal("listen failed");

    while(1) {                        //(4)
        sa = accept(s, 0, 0);         //(5)
        if (sa < 0)
            fatal("accept failed");
       
        read(sa, buf, BUF_SIZE);      //(6)
       
        fd = open(buf, O_RDONLY);     //(7)
        if (fd < 0)
            fatal("open failed");

        while(1) {
            bytes = read(fd, buf, BUF_SIZE);
            if (bytes <= 0)
                break;
            write(sa, buf, bytes);
        }
        close(fd);
        close(sa);
    }
}

(1) setsockopt调用是必要的,它允许这个端口可以被重复使用,所以服务器能永久地运行,处理一个又一个请求。
(2) IP地址被绑定到套接字中
(3) 初始化过程中的最后一步调用listen,这样就宣告了本服务器愿意接受进来的调用,并告诉系统,当服务器在处理请求时如果有新的请求到来的话,请系统保留多达QUEUE_SIZE个请求。如果队列满了之后又有新的请求到来,则直接将后来的请求丢弃即可。
(4) 到这个点上,服务器进入它的主循环,这是一个永不退出的循环。终止服务器的唯一做法是从外部将服务器杀死(kill)
(5) accept调用阻塞服务器,直到某个客户试图与它建立连接为止。如果accept调用成功,则它返回一个文件描述符,利用这个文件描述符可以进行读写操作,就好像利用文件描述符从管道读写数据一样。然后,管道是单向的,与此不同的是,套接字是双向的,所以,sa(socket address,套接字地址)既可以被用来从连接中读取数据,也可以被用来向连接写数据。
(6) 连接被建立起来以后,服务器从连接中读取文件名。如果文件名还没有被发送过来,则服务器阻塞住,以等待文件名的到来。
(7) 服务器获得了文件名之后,它打开该文件,然后进入一个循环,在循环体中它交替地从文件中读取数据块并且将数据块写到套接字中,这个过程一直持续到整个文件被复制完成为止。然后服务器关闭文件和连接,并等待下一个连接的到来。


client.c
--------------------------------------------
#include <stdio.h>
#include <fcntl.h>    // O_CREAT, O_RDWR
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>

#define SERVER_PORT 12345
#define BUF_SIZE     4096

int fatal(char *string)
{
    printf("%s\n", string);
    exit(1);
}

int main(int argc, char **argv)
{
    int c, s, bytes, fd;
    char buf[BUF_SIZE];
    struct hostent *h;
    struct sockaddr_in channel;

    if(argc != 3)
        fatal("Usage: client servername file-name");
    h = gethostbyname(argv[1]);         //(1)
    if(!h)
        fatal("gethostbyname failed");

    s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);               //(2)
    if (s < 0)
        fatal("socket");
    memset(&channel, 0, sizeof(channel));
    channel.sin_family = AF_INET;
    memcpy(&channel.sin_addr.s_addr, h->h_addr, h->h_length);
    channel.sin_port = htons(SERVER_PORT);

    c = connect(s, (struct sockaddr *)&channel, sizeof(channel));//(3)
    if (c < 0)
        fatal("connect failed");

    write(s, argv[2], strlen(argv[2]) + 1);                      //(4)
    fd = open(argv[2], O_CREAT|O_RDWR, 0666);
    while (1) {
        bytes = read(s, buf, BUF_SIZE);
        if (bytes <= 0)
            exit(0);
        write(fd, buf, bytes);
    }
}

(1) argv[1]包含了服务器的名字,通过gethostbyname它被转换为一个IP地址,这里的函数gethostbyname使用DNS来查询机器名。
(2) 客户创建一个套接字并进行一些初始化工作
(3) 客户使用connect函数,企图与服务器建立一个TCP连接。如果在指定名字的服务器上,服务器程序已经启动和运行了,并且它被绑定到SERVER_PORT端口上,而且服务器当前是空闲的,或者在listen队列中还有空间,那么,连接(最终)将被建立起来。
(4) 客户利用该连接可以将文件的名字发送过去,做法很简单,只要在套接字上执行写操作即可。发送的字节数是文件名字长度加1,因为名字尾部的0字节必须被发送过去,以便告诉服务器文件名在哪里结束。



编译运行
--------------------------------------------
将server.c放在服务器上编译运行:
# gcc server.c -o server
# ./server
在服务器上放置下载文件:
# vi tcp
Hi TCP/IP


将client.c放在客户端上编译运行:
# gcc client.c -o client
配置客户端的DNS:
# vi /etc/hosts
192.168.0.240   server
下载文件tcp
# ./client server tcp
# more tcp
Hi TCP/IP

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值