网络编程入门

Linux下网络编程

socket函数

#include <sys/socket.h>
int socket(int domain, int type, int protocal);

成功时返回文件描述符,失败时返回-1

bind函数

#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);

成功时返回0,失败时返回-1

listen函数

#include <sys/socket.h>
int listen(int sockfd, int backlog);

成功时返回0,失败时返回-1

accept函数

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

成功时返回0,失败时返回-1

connect函数

#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);

成功时返回0,失败时返回-1

open函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int flag);

成功时返回文件描述符,失败时返回-1

打开模式 含义
O_CREAT 必要时创建文件
O_TRUNC 删除全部现有数据
O_APPEND 维持现有数据,保存到其后面
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读写打开

close函数

#include <unistd.h>
int close(fd);

成功时返回0,失败时返回-1

write函数

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);

成功时返回写入的字节数,失败时返回-1
- fd: 显示数据传输对象的文件描述符
- buf: 保存要传输数据的缓冲地址值
- nbytes: 要传输数据的字节数

read函数

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);

成功时返回接收的字节数(但遇到文件结尾则返回0),失败时返回-1
- fd: 显示数据传输对象的文件描述符
- buf: 要保存接收数据的缓冲地址值
- nbytes: 要传输数据的字节数

网络编程中接受连接请求的套接字创建过程可整理如下:

  • 调用socket函数创建套接字
  • 调用bind函数分配IP地址和端口号
  • 调用listen函数转为可接收请求状态
  • 调用accept函数受理连接请求

server.cpp

#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
using namespace std;

/*
 * 网络编程中接受连接请求的套接字创建过程可整理为:
 * 1. 调用socket函数创建套接字
 * 2. 调用bind函数分配IP地址和端口号
 * 3. 调用listen函数转为可接收请求状态
 * 4. 调用accept函数受理连接请求 
 * */

void error_handling(string message);

int main(int argc, char ** argv) {
  int serv_sock;
  int clnt_sock;

  struct sockaddr_in serv_addr;
  struct sockaddr_in clnt_addr;
  socklen_t clnt_addr_size;

  char message[] = "hello, world";

  if (argc != 2) {
    printf("Usage: %s <port>\n", argv[0]);
    exit(1);
  }

  serv_sock = socket(PF_INET, SOCK_STREAM, 0);
  if (serv_sock == -1) 
    error_handling("socket() error");

  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_port = htons(atoi(argv[1]));

  if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
    error_handling("bind() error");

  if (listen(serv_sock, 5) == -1)
    error_handling("listen() error");

  clnt_addr_size = sizeof(clnt_addr);
  clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr,  &clnt_addr_size);
  if (clnt_sock == -1)
    error_handling("accept() error");

  write(clnt_sock, message, sizeof(message));
  close(clnt_sock);
  close(serv_sock);
  return 0;
}

void error_handling(string message) {
  cerr << message << endl;
  exit(1);
}

client.cpp

#include <cerrno>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

using namespace std;

void error_handling(string message);

int main(int argc, char ** argv) {
  int sock;
  struct sockaddr_in serv_addr;
  char message[30];
  int str_len;

  if (argc != 3) {
    cout << "Usage: " << argv[0] << " <IP> <port>" << endl;
    exit(1);
  }

  sock = socket(PF_INET, SOCK_STREAM, 0);
  if (sock == -1) 
    error_handling("socket() error");

  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
  serv_addr.sin_port = htons(atoi(argv[2]));

  if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
    close(sock);
    cout << "errno = " << errno << endl;
    error_handling("connect() error");
  }

  str_len = read(sock, message, sizeof(message) - 1);
  if (str_len == -1) {
    close(sock);
    error_handling("read() error");
  }

  cout << "Message from server: " << message << endl;
  close(sock);
  return 0;
}
void error_handling(string message) {
  cerr << message << endl;
  exit(1);
}

Windows下网络编程

WSAStartup函数

#include <winsock2.h>
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

成功时返回0,失败时返回非0的错误代码值
- wVersionRequested: 程序员要用的Winsock版本
- lpWSAData: WSADATA结构体变量的地址值
- 一般使用4位16进制数表示版本,高8位为副版本号,低8位为主版本号,如0x0201即表示主版本号为1副版本号为2的版本,即1.2版本,通常借助MAKEWORD宏函数MAKEWORD(1,2)表示1.2版本
- lpWSADATA是WSADATA的指针类型

WSAStartup函数调用过程

int main(int argc, char ** argv) {
    WSADATA wsaData;
    ....
    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) 
        error_handling("WSAStartup() error");
    ....
    return 0;
}

WSACleanup函数

#include <winsock2.h>
int WSACleanup(void);

成功时返回0,失败时返回SOCKET_ERROR\
调用此函数时,Winsock相关库将归还Windows系统,无法再调用Winsock相关函数

socket函数

#include <winsock2.h>
SOCKET socket(int af, int type, int protocal);

成功时返回套接字句柄,失败时返回INVALID_SOCKET

bind函数

#include <winsock2.h>
int bind(SOCKET s, const struct sockaddr *name, int namelen);

成功时返回0,失败时返回SOCKET_ERROR

listen函数

#include <winsock2.h>
int listen(SOCKET s, int backlog);

成功时返回0,失败时返回SOCKET_ERROR

accept函数

#include <winsock2.h>
SOCKET accept(SOCKET s, struct sockaddr * addr, int *addrlen);

成功时返回套接字句柄,失败时返回INVALID_SOCKET

connect函数

#include <winsock2.h>
int connect(SOCKET s, const struct sockaddr * name, int namelen);

成功时返回0,失败时返回SOCKET_ERROR

closesocket函数

#include <winsock2.h>
int closesocket(SOCKET s);

成功时返回0,失败时返回SOCKET_ERROR

send函数

#include <winsock2.h>
int send(SOCKET s, const char *buf, int len, int flags);

成功时返回传输字节数,失败时返回SOCKET_ERROR
- s: 表示数据传输对象连接的套接字句柄
- buf: 保存带传输数据的缓冲地址值
- len: 要传输的字节数
- flags: 传输数据时用到的多种选项信息

recv函数

#include <winsock2.h>
int recv(SOCKET s, const char *buf, int len, int flags);

成功时返回接收的字节数(收到EOF时为0),失败时返回SOCKET_ERROR
- s: 表示数据传输对象连接的套接字句柄
- buf: 保存接收数据的缓冲地址值
- len: 能够接收的最大字节数
- flags: 接收数据时用到的多种选项信息

server.cpp

#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <WinSock2.h>
using namespace std;

void ErrorHandling(string message);

int main(int argc, char ** argv) {
    WSADATA wsaData;
    SOCKET hServSock, hClntSock;
    SOCKADDR_IN servAddr, clntSock;

    char message[] = "hello, world";
    if (argc != 2) {
        cout << "Usage: " << argv[0] << " <port>" << endl;
        exit(1);
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) == INVALID_SOCKET)
        ErrorHandling("WSAStartup() error");

    hServSock = socket(PF_INET, SOCK_STREAM, 0);
    if (hServSock == SOCKET_ERROR)
        ErrorHandling("socket() error");

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(atoi(argv[1]));

    if (bind(hServSock, (SOCKADDR *)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {
        closesocket(hServSock);
        ErrorHandling("bind() error");
    }

    if (listen(hServSock, 5) == SOCKET_ERROR) {
        closesocket(hServSock);
        ErrorHandling("listen() error");
    }

    int szClntSock = sizeof(clntSock);
    hClntSock = accept(hServSock, (SOCKADDR *)&clntSock, &szClntSock);
    if (hClntSock == INVALID_SOCKET) {
        closesocket(hServSock);
        ErrorHandling("accept() error");
    }

    send(hClntSock, message, sizeof(message), 0);

    closesocket(hServSock);
    closesocket(hClntSock);
    WSACleanup();
    return 0;
}

void ErrorHandling(string message) {
    WSACleanup();
    cerr << message << endl;
    exit(1);
}

client.cpp

#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <WinSock2.h>
using namespace std;

void ErrorHandling(string message);

int main(int argc, char ** argv) {
    WSADATA wsaData;
    SOCKET hSocket;
    SOCKADDR_IN servAddr;

    char message[30];
    int strLen;
    if (argc != 3) {
        cout << "Usage: " << argv[0] << "<IP> <port>" << endl;
        exit(1);
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        ErrorHandling("WSAStartup() error");

    hSocket = socket(PF_INET, SOCK_STREAM, 0);
    if (hSocket == INVALID_SOCKET)
        ErrorHandling("socket() error");

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = inet_addr(argv[1]);
    servAddr.sin_port = htons(atoi(argv[2]));

    if (connect(hSocket, (SOCKADDR *)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {
        closesocket(hSocket);
        ErrorHandling("connect() error");
    }

    strLen = recv(hSocket, message, sizeof(message) - 1, 0);
    if (strLen == -1) {
        closesocket(hSocket);
        ErrorHandling("recv() error");
    }

    cout << "Message from server: " << message << endl;

    closesocket(hSocket);
    WSACleanup();
    return 0;
}

void ErrorHandling(string message) {
    WSACleanup();
    cerr << message << endl;
    exit(1);
}

运行结果

客户端

服务端

posted @ 2017-07-10 00:53  _Wilbert  阅读(181)  评论(0编辑  收藏  举报