Chinaunix首页 | 论坛 | 博客
  • 博客访问: 474144
  • 博文数量: 117
  • 博客积分: 3195
  • 博客等级: 中校
  • 技术积分: 1156
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-04 01:44
文章分类

全部博文(117)

文章存档

2012年(5)

2011年(5)

2010年(46)

2009年(61)

我的朋友

分类:

2010-01-08 16:18:28

#include <stdio.h>
#include <winsock.h>
#include <string.h>
#pragma comment (lib, "ws2_32")
#define SERVER_PORT 8888    /*服务端口*/
#define MAX_MSG_SIZE 2048    /*缓冲区大小*/
#define BACKLOG 5        /*等待服务的最大数*/

int Server_Proc(int sock)
{
    int n;
    char msg[MAX_MSG_SIZE];
    n = recv(sock, msg, MAX_MSG_SIZE, 0);
    msg[n] = 0;
    printf("%s\n", msg);
    strcpy(msg, "hi, i am server!");
    n = send(sock, msg, strlen(msg), 0);
    closesocket(sock);
    return 1;
}

int main()
{
    int ser_sock, /*服务器SOCKET*/
        cli_sock;    /*客户端SOCKET*/
    int addrlen;    /*地址长度*/
    char hostname[255];    /*主机名*/
    PHOSTENT hptr;        /*主机地址*/

    struct sockaddr_in ser_addr,    /*服务器地址*/
                        cli_addr;    /*客户端地址*/

    WSADATA WSAData;
    if(WSAStartup(MAKEWORD(2,2), &WSAData) != 0)
    {
        fprintf(stderr, "WSAStartup failed:%d\n", WSAGetLastError());
        exit(1);
    }

    /*获得本地主机名,并输出IP地址*/
    if(gethostname(hostname, sizeof(hostname)) != 0)    
    {
        errno = GetLastError();
        fprintf(stderr,"gethostname Error:%d\n", errno);
        return 1;
    }
    hptr = gethostbyname(hostname);
    printf("IP: %s\n", inet_ntoa(*(struct in_addr*) *hptr->h_addr_list));

    /*创建连接的SOCKET*/
    ser_sock = socket(AF_INET, SOCK_STREAM, 0);
    if(ser_sock < 0)
    {
        fprintf(stderr, "socket error : %d\n", GetLastError());
        exit(1);
    }
    
    /*初始化服务器地址*/
    addrlen = sizeof(struct sockaddr_in);
    memset(&ser_addr, 0, addrlen);
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    ser_addr.sin_port = htons(SERVER_PORT);

    /*绑定socket和本地地址*/
    if(bind(ser_sock, (struct sockaddr*)&ser_addr,
        addrlen)<0)
    {
        fprintf(stderr, "Bind error:%d\n", GetLastError());
        exit(1);
    }

    /*侦听客户端请求*/
    if(listen(ser_sock, BACKLOG) < 0)
    {
        fprintf(stderr, "listen error: %d\n", GetLastError());
        closesocket(ser_sock);
        exit(1);
    }

    printf("waiting for client....\n");
    while(1)
    {
        cli_sock = accept(ser_sock, (struct sockaddr*)&cli_addr, &addrlen);
        /*对连接建立请求的响应,返回新的socket,*/
        if(cli_sock <= 0)
            fprintf(stderr, "Accept error:%d\n", GetLastError());
        else
            Server_Proc(cli_sock);
    }
    closesocket(ser_sock);
    WSACleanup();
    return 0;
}

工作流程:

服务器端调用socket初始化,bind 端口和地址,listen 客户端的请求,再调用accept 阻塞等待客户连接请求,处于监听端口状态;客户端调用socket初始化,再调用connect请求连接服务器,连接成功后,服务器端也从accept返回,返回一个新的cli_socket,用于跟客户端进行通信;通信完后,客户端关闭socket,服务器端关闭cli_socket。由于服务器端有个while(1),accept处于一直等待状态,所以还可以和新的客户端通信。

函数说明:

(1)socket  创建套接字

原型:SOCKET socket (int af, int type, int protocol)

af指定通信协议类型,通常为AF_INET; type指定套接字类型,流式套接字为SOCK_STREAM;protocol为指定套接字使用的特定协议,通常为IPPROTO_IP,值为0. 成功后返回新创建的套接字描述符。

(2)closesocket  关闭套接字

原型: int closesocket(SOCKET s)

参数是要关闭的套接字描述符,成功返回0

(3)bind   绑定本地地址和套接字

原型:int bind (SOCKET s, const struct sockaddr FAR *addr, int namelen)

s是要绑定的套接字描述符,addr指定sockaddr结构的套接字地址, namelen是套接字地址结构长度。成功后返回0

(4)listen  监听端口的连接建立请求

原型:int listen(SOCKET s, int backlog)

s为要监听的套接字描述符,backlog是客户连接请求队列最多容纳backlog个客户,成功返回0.

(5)accept 对建立连接请求的响应

原型:SOCKET accept (SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen)

s为要监听的套接字描述符;addr返回新创建的套接字地址结构, addrlen该地址结构的长度,成功返回新创建的套接字描述符。

一个结构体:

struct sockaddr_in {
        short sin_family;  //网络地址类型,AF_INET
        u_short sin_port;  //使用的端口号
        struct in_addr sin_addr;   //使用的IP地址,INADDR_ANY表示所有IP地址
        char sin_zero[8];   //填充字段,为了使sockaddr_in可转化为sockaddr
};


阅读(835) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~