020-29133788
    资 讯
    您的位置:首页 >> 资 讯 >> 软件应用 >> 编程开发 >> 正文
    关于网路程式 (UNIX Socket + WinSock)

    点击:   发布日期:2013-01-19

    本文来自 www.020fix.com

    相关函式:
    int socket(int PROTOCOL_FAMILY, int SOCKET_TYPE, int PROTOCOL);
    int bind(int SOCK_FD, const struct sockaddr *SERVER_SIDE_ADDR, socklen_t ADDR_LEN);
    int listen(int SOCK_FD, int BACKLOG);
    int accept(int SOCK_FD, struct sockaddr *CLIENT_SIDE_ADDR, socklen_t *ADDR_LEN);
    int connect(int SOCK_FD, const struct sockaddr *SERVER_SIDE_ADDR, socklen_t ADDR_LEN);
    int close(int FD);
    int shutdown (int s, int how);

    int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
    int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
    int fcntl(int fd, int cmd);
    int fcntl(int fd, int cmd, long arg);
    int fcntl(int fd, int cmd, struct flock *lock);
    int select(int n, fd_set *READ_FD_SET, fd_set *WRITE_FD_SET, fd_set *EXCEPT_FD_SET, struct timeval *timeout);

    ssize_t read(int fd, void *buf, size_t count);
    ssize_t recv(int SOCK_FD, void *buf, size_t len, int flags);
    ssize_t write(int fd, const void* buf, size_t count);
    ssize_t send(int SOCK_FD, const void* buf, size_t len, int flags)

    pid_t fork(void);
    pid_t wait(int *status);
    pid_t waitpid(pid_t pid, int* status, int options);
    pid_t waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

    socket - 建立 Socket
    bind - 把已经建立好的 Socket 与 Socket Address 做相互关联
    listen - 开始监听该 Socket Address
    accept - 接受连线要求
    connect - 发出连线要求
    shutdown - 关闭连线

    read/recv - 从 file descriptor 读取资料
    write/send - 把资料写入 file descriptor

    getsockopt - 读取 socket 设定值
    setsockopt - 设定 socket
    fcntl - 做 file descriptor 的控制设定
    select - 检查 FD_SETS 是否为可操作,如果是,就立刻返回,否则等到可操作或是 Timeout 才返回

    fork - 建立子程序 (child process)
    waitxxx - 等待某特定程序或某群组的所有程序结束或是状态改变
    kill - 发送信号 (signal) 给某特定程序,或某群组的所有程序

    Server Side:
    1. 建立 Socket
    2. bind socket to address
    3. 开始监听
    4. 如果有连线要求 (accept),检查 REMOTE_ADDRESS 是否为可连线对象。
       如果是,接受连线,开始 Server - Client Communication
           否,把 accept 传回的 SOCKET_FD shutdown 掉 (关闭连线)
       并继续查看是否有其他连线要求

    Client Side:
    1. 建立 Socket
    2. 发出连线要求 (connect),若传回值为 0 => 连线成功, -1 => 连线失败
    3. 如果连线成功,开始 Server - Client Communication

    --
    先写到这里,下次再继续
    关于网路程式的部份,都是自学的 (自己查 linux 的 manual)
    如果有错误或是需要补充的部份,欢迎指正

    Windows 用的是 winsock
    它的整体流程是差不多的,
    不过要先用 WSAStartup 来做起始设定,
    结束后要用 WSACleanup 来释放 WinSock 所用到的空间
    使用起来比 unix 上面的要多一些东西
    WSA* 都是 winsock 里面的函式
    这些在 MSDN 里面都查得到

    下面这个是几个月前才贴过的程式
    复制内容到剪贴板
    代码:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #ifdef WIN32
    #include <process.h>
    #include <winsock2.h>
    #define strncasecmp strnicmp
    #endif

    #define MAX_LINE_LENGTH 42
    #define MAX_RECORD_COUNT 1000
    #define RECORD_SIZE 40
    #define BUFFER_SIZE 1024

    struct Person {
            char Name[6];
            char ID[10];
            char Mobile[10];
            char BirthYear[2];
            char BirthMonth[2];
            char BirthDay[2];
            char SN[8];
    } Records[MAX_RECORD_COUNT];
    int RecordCount=0;

    int FetchViaHTTP(char* url) {
            char* sHost, *host;
            char* sPort;
            char* sLocation;
            struct sockaddr_in remote_addr;
            struct hostent *hostaddr;
    #ifdef WIN32
            WSADATA wsaData;
            int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
            if (iResult != NO_ERROR) {
                    printf("Error at WSAStartup()\n");
                    return -1;
            }
    #endif
            remote_addr.sin_family=AF_INET;
            sHost = &url[7];
            sPort = strpbrk(&url[7], ":/");
            host = (char*) malloc(sPort-sHost+1);
            strncpy(host, sHost, sPort-sHost);
            host[sPort-sHost]='\0';
            if (!sPort) {
                    WSACleanup();
                    free(host);
                    return -1;
            }
            if (*sPort==':')
                    remote_addr.sin_port = htons(strtol(&sPort[1], &sLocation, 0));
            else {
                    sLocation=sPort;
                    remote_addr.sin_port=htons(80);
            }
            if (*sLocation!='/') {
                    WSACleanup();
                    free(host);
                    return -1;
            }
            hostaddr=gethostbyname(host);
            if (!hostaddr) {
                    printf("Resolve Host Address Failed : %ld\n", WSAGetLastError());
                    WSACleanup();
                    free(host);
                    return -1;
            }
            remote_addr.sin_addr.S_un.S_un_b.s_b1=hostaddr->h_addr_list[0][0];
            remote_addr.sin_addr.S_un.S_un_b.s_b2=hostaddr->h_addr_list[0][1];
            remote_addr.sin_addr.S_un.S_un_b.s_b3=hostaddr->h_addr_list[0][2];
            remote_addr.sin_addr.S_un.S_un_b.s_b4=hostaddr->h_addr_list[0][3];
            {
    #ifdef WIN32
                    SOCKET sock_remote;
                    sock_remote=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                    if (sock_remote == INVALID_SOCKET) {
                            printf("Error at socket(): %ld\n", WSAGetLastError());
                            WSACleanup();
                            free(host);
                            return -1;
                    }
                    if (connect(sock_remote, &remote_addr, sizeof(struct sockaddr_in))) {
                            printf("Error at connecting remote host : %ld\n", WSAGetLastError());
                            WSACleanup();
                            free(host);
                            return -1;
                    }
    #endif
                    send(sock_remote, "GET ", 4, 0);
                    send(sock_remote, sLocation, strlen(sLocation), 0);
                    send(sock_remote, "\n", strlen("\n"), 0);
                    {
                            char buffer[MAX_LINE_LENGTH];
                            int len, i, rest=0;
                            while ((len=recv(sock_remote, &buffer[rest], MAX_LINE_LENGTH-rest, 0))>0) {
                                    i=0;
                                    while (len+rest>=i+RECORD_SIZE) {
                                            memcpy(&Records[RecordCount++], &buffer[i], RECORD_SIZE);
                                            for (i=40;i<len+rest && buffer[i]!='\n';i++);
                                            i++;
                                    }
                                    rest = len+rest - i;
                            }
                    }
            }
    #ifdef WIN32
            WSACleanup();
    #endif
            free(host);
            return 0;
    }
    int FetchLocal(const char* fname) {
            FILE* fp;
            char buffer[MAX_LINE_LENGTH];
            if ((fp=fopen(fname, "r"))!=NULL) {
                    while (fgets(buffer, MAX_LINE_LENGTH, fp))
                            memcpy(&Records[RecordCount++], buffer, RECORD_SIZE);
                    fclose(fp);
                    return 0;
            }
            printf("Error Open File : %s\n", strerror(errno));
            return -1;
    }

    void CalcBirth(int birth[2][12]) {
            int i;
            for (i=0;i<12;i++)
                    birth[0][i]=birth[1][i]=0;
            for (i=0;i<RecordCount;i++)
                    birth[Records[i].ID[1]-'1'][(Records[i].BirthMonth[0]-'0')*10+(Records[i].BirthMonth[1]-'0')-1]++;
    }

    int CountFamilyName(void) {
            char FamilyNames[MAX_RECORD_COUNT][2];
            int i, j, counter=0, duplicated=0;
            for (i=0;i<RecordCount;i++) {
                    for (j=0, duplicated=0;j<counter && !duplicated;j++)
                            if (!strncmp(FamilyNames[j], Records[i].Name, 2))
                                    duplicated=1;
                    if (!duplicated)
                            memcpy(&FamilyNames[counter++], Records[i].Name, 2);
            }
            return counter;
    }

    int main(int argc, char** argv) {
            int FetchResult, i;
            int Birth[2][12];
            char FamilyName[MAX_RECORD_COUNT][2];
            int FamilyNameCount;
            if (argc<2) return -1;
            else if (!strncasecmp(argv[1], "http://", 7)) {
                    FetchResult=FetchViaHTTP(argv[1]);
            } else {
                    FetchResult=FetchLocal(argv[1]);
            }
            if (FetchResult) {
                    printf("Error Loading Data (%d) : %s\n", FetchResult, strerror(errno));
                    return -1;
            }
            CalcBirth(Birth);
            printf("共输入 %2d 人\n\n", RecordCount);
            printf("各月生日人数统计如下:\n月 份:   1   2   3   4   5   6   7   8   9  10  11  12\n");
            printf("男生数:");
            for (i=0;i<12;i++)
                    printf("%4d", Birth[0][i]);
            printf("\n女生数:");
            for (i=0;i<12;i++)
                    printf("%4d", Birth[0][i]);
            printf("\n\n");
            printf("共有 %d 不同姓氏的人\n", CountFamilyName());
            getch();
            return 0;
    }
    用 WinSock 连上 Web Server,
    读取某个档案后,作一些楚理,在显示出了的程式