《TCP/IP网络编程》第1章 理解网络编程和套接字

92 篇文章 18 订阅
34 篇文章 3 订阅

Linux套接字

相关函数

创建套接字

#include <sys/socket.h>
//成功返回文件描述符,失败返回-1
int socket(int domain, int type, int protocol);

端口复用

int opt = 1;
int setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));

绑定IP和Port

#include <sys/socket.h>
//成功返回0,失败返回-1
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);

监听

#include <sys/socket.h>
//成功返回0,失败返回-1
int listen(int sockfd, int backlog);

获取连接

#include <sys/socket.h>
//成功返回文件描述符,失败返回-1
int accept(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);

请求连接

#include <sys/socket.h>
//成功返回0,失败返回-1
int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);

服务器端

01.hello_server_linux.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define PORT 9999

void error_handling(const char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char *argv[])
{
    int serv_sock = socket(PF_INET, SOCK_STREAM, 0);
    if (serv_sock == -1)
        error_handling("socket() error!");

    const int opt = 1;
    if (setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)) == -1)
        error_handling("setsockopt() error!");

    socklen_t addr_size = sizeof(struct sockaddr_in);

    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, addr_size);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(PORT);

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

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

    struct sockaddr_in clnt_addr;
    int clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &addr_size);
    if (clnt_sock == -1)
        error_handling("accept() error!");

    char message[] = "Hello World!";
    write(clnt_sock, message, sizeof(message) - 1);
    close(clnt_sock);

    close(serv_sock);

    return 0;
}

// gcc 01.hello_server_linux.c -o 01.hello_server_linux && ./01.hello_server_linux

客户端

01.hello_client_linux.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define IP "127.0.0.1"
#define PORT 9999

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

int main(int argc, char *argv[])
{
	int sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == -1)
		error_handling("socket() error!");

	socklen_t addr_size = sizeof(struct sockaddr_in);

	struct sockaddr_in addr;
	memset(&addr, 0, addr_size);
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(IP);
	addr.sin_port = htons(PORT);

	if (connect(sock, (struct sockaddr *)&addr, addr_size) == -1)
		error_handling("connect() error!");

	char message[30];
	int str_len = read(sock, message, sizeof(message) - 1);
	if (str_len == -1)
		error_handling("read() error!");
	message[str_len] = '\0';

	printf("Message from server : %s\n", message);

	close(sock);

	return 0;
}

// gcc 01.hello_client_linux.c -o 01.hello_client_linux && ./01.hello_client_linux

Linux文件操作

文件描述符

0,标准输入Standard Input
1,标准输出Standard Output
2,标准错误Standard Error

打开文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//成功返回文件描述符,失败返回-1
int open(const char *path, int flag);
//flag位或运算
//O_CREAT,不存在时创建
//O_TRUNC,删除
//O_APPEND,追加
//O_RDONLY,只读
//O_WRONLY,只写
//O_RDWR,读写

关闭文件

#include <unistd.h>
//成功返回0,失败返回-1
int close(int fd);

写入文件

#include <unistd.h>
//成功返回写入字节数,失败返回-1
ssize_t write(int fd, const void *buf, size_t nbytes);
//size_t, unsigned int
//ssize_t, signed int
//操作系统定义数据类型添加后缀_t
01.low_open.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

void error_handling(const char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

int main(int argc, char *argv[])
{
	int fd = open("data.txt", O_CREAT | O_WRONLY | O_TRUNC);
	if (fd == -1)
		error_handling("open() error!");
	printf("file descriptor: %d\n", fd);

	char buf[] = "Let's go!\n";
	if (write(fd, buf, strlen(buf)) == -1)
		error_handling("write() error");

	close(fd);

	return 0;
}

// gcc 01.low_open.c -o 01.low_open && ./01.low_open && cat data.txt

读取文件

#include <unistd.h>
//成功返回接收字节数(预计末尾返回0),失败返回-1
ssize_t read(int fd, const void *buf, size_t nbytes);
01.low_read.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#define BUF_SIZE 128

void error_handling(const char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

int main(int argc, char *argv[])
{
	int fd = open("data.txt", O_RDONLY);
	if (fd == -1)
		error_handling("open() error");
	printf("file descriptor: %d\n", fd);

	char buf[BUF_SIZE];
	int strLen = read(fd, buf, sizeof(buf) - 1);
	if (strLen == -1)
		error_handling("read() error");
	buf[strLen] = '\0';
	printf("file data: %s\n", buf);

	close(fd);

	return 0;
}

// gcc 01.low_read.c -o 01.low_read && ./01.low_read

文件描述符和套接字

01.fd_seri.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#ifdef _WIN32
#include <winsock2.h>
void ErrorHanding(const char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
#else
#include <sys/socket.h>
#endif

int main(int argc, char *argv[])
{
	int fd2 = open("test.dat", O_CREAT | O_WRONLY | O_TRUNC);
	printf("file descriptor 2: %d\n", fd2);
	close(fd2);

#ifdef _WIN32
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHanding("WSAStartup() error!");

	SOCKET fd1 = socket(PF_INET, SOCK_STREAM, 0);
	if (fd1 == INVALID_SOCKET)
		ErrorHanding("socket() error");
	SOCKET fd3 = socket(PF_INET, SOCK_STREAM, 0);
	if (fd3 == INVALID_SOCKET)
		ErrorHanding("socket() error");

	printf("file descriptor 1: %llu\n", fd1);
	printf("file descriptor 3: %llu\n", fd3);

	closesocket(fd1);
	closesocket(fd3);

	WSACleanup();
#else
	int fd1 = socket(PF_INET, SOCK_STREAM, 0);
	int fd3 = socket(PF_INET, SOCK_STREAM, 0);
	printf("file descriptor 1: %d\n", fd1);
	printf("file descriptor 3: %d\n", fd3);
	close(fd1);
	close(fd3);
#endif

	return 0;
}

// linux
// gcc 01.fd_seri.c -o 01.fd_seri && ./01.fd_seri

// mingw
// gcc 01.fd_seri.c -o 01.fd_seri -lws2_32 && 01.fd_seri

Windows套接字

winsock2.h
ws2_32.lib

相关函数

Winsock初始化

#include <winsock2.h>
//成功0
//WORD, unsigned short
//MAKEWORD(1, 2); //主版本1,副版本2,返回0x0201
//MAKEWORD(2, 2); //主版本2,副版本2,返回0x0202
//LPWSADATA, WSADATA指针 
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

Winsock销毁

#include <winsock2.h>
//成功0,失败SOCKET_ERROR
int WSACleanup(void);

socket

#include <winsock2.h>
//成功返回套接字句柄,失败INVALID_SOCKET
SOCKET socket(int af, int type, int protocol);

setsockopt

//端口复用
int opt = 1;
int setsockopt(hServSock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));

bind

#include <winsock2.h>
//成功0,失败SOCKET_ERROR
int bind(SOCKET s, const struct sockaddr *name, int namelen);

listen

#include <winsock2.h>
//成功0,失败SOCKET_ERROR
int listen(SOCKET s, int backlog);

accept

#include <winsock2.h>
//成功返回套接字句柄,失败INVALID_SOCKET
SOCKET accept(SOCKET s, struct sockaddr *addr, int addrlen);

connect

#include <winsock2.h>
//成功返回套接字句柄,失败INVALID_SOCKET
SOCKET connect(SOCKET s, const struct sockaddr *name, int namelen);

closesocket

#include <winsock2.h>
//成功0,失败SOCKET_ERROR
int closesocket(SOCKET s);

send

#include <winsock2.h>
//成功字节数,失败SOCKET_ERROR
int send(SOCKET s, const char *buf, int len, int flags);

recv

#include <winsock2.h>
//成功字节数(收到EOF为0),失败SOCKET_ERROR
int recv(SOCKET s, const char *buf, int len, int flags);

服务器端

01.hello_server_win.c
#include <stdio.h>
#include <winsock2.h>

#define PORT 9999

void ErrorHanding(const char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char *argv[])
{
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        ErrorHanding("WSAStartup() error!");

    SOCKET hServSock = socket(PF_INET, SOCK_STREAM, 0);
    if (hServSock == INVALID_SOCKET)
        ErrorHanding("socket() error!");

    const int opt = 1;
    if (setsockopt(hServSock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) < 0)
        ErrorHanding("setsockopt() error!");

    int szAddr = sizeof(SOCKADDR_IN);

    SOCKADDR_IN servAddr;
    memset(&servAddr, 0, szAddr);
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(PORT);

    if (bind(hServSock, (SOCKADDR *)&servAddr, szAddr) == SOCKET_ERROR)
        ErrorHanding("bind() error!");

    if (listen(hServSock, 5) == SOCKET_ERROR)
        ErrorHanding("listen() error!");

    SOCKADDR_IN clntAddr;
    SOCKET hClntSock = accept(hServSock, (SOCKADDR *)&clntAddr, &szAddr);
    if (hClntSock == INVALID_SOCKET)
        ErrorHanding("accept() error!");

    char message[] = "Hello World!";
    send(hClntSock, message, sizeof(message)-1, 0);
    closesocket(hClntSock);

    closesocket(hServSock);

    WSACleanup();

    return 0;
}

// gcc 01.hello_server_win.c -o 01.hello_server_win -lws2_32  && 01.hello_server_win

客户端

01.hello_client_win.c
#include <stdio.h>
#include <winsock2.h>

#define IP "127.0.0.1"
#define PORT 9999

void ErrorHanding(const char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char *argv[])
{
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        ErrorHanding("WSAStartup() error!");

    SOCKET hSock = socket(PF_INET, SOCK_STREAM, 0);
    if (hSock == INVALID_SOCKET)
        ErrorHanding("socket() error!");

    const int szAddr = sizeof(SOCKADDR_IN);

    SOCKADDR_IN servAddr;
    memset(&servAddr, 0, szAddr);
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = inet_addr(IP);
    servAddr.sin_port = htons(PORT);

    if (connect(hSock, (SOCKADDR *)&servAddr, szAddr) == SOCKET_ERROR)
        ErrorHanding("connect() error!");

    char message[30];
    int strLen = recv(hSock, message, sizeof(message) - 1, 0);
    if (strLen == -1)
        ErrorHanding("read() error!");
    message[strLen] = '\0';
    printf("Message from server: %s\n", message);

    closesocket(hSock);

    WSACleanup();

    return 0;
}

// gcc 01.hello_client_win.c -o 01.hello_client_win -lws2_32  && 01.hello_client_win

visual studio命令行编译

基本操作

搜索Develop Command Prompt

cl /help
/Fe:main.exe 指定exe名称
/std:c11
/LD /Fo:out.DLL 生成动态库
/I include目录

cl /EHsc main.cpp /Fe:main.exe
cl /EHsc main2.cpp func.cpp /link
cl /EHsc hello.c /Fe:hello.exe /link ws2_32.lib

可执行文件

cl src1.cpp src2.cpp /ID:\opencv\include /Fe:out.exe
/I 添加头文件目录
/Fe 指明输出exe名

静态链接库

cl /c src1.cpp src2.cpp  # 只编译出obj文件,不进行链接
LIB.EXE /OUT:MYLIB.LIB FILE1.OBJ FILE2.OBJ

动态链接库

cl /LD src1.cpp src2.cpp /ID:\opencv\include /link /Fo::out.dll
LINK.EXE /DLL /OUT:MYLIB.DLL FILE3.OBJ FILE4.OBJ

编译运行

cl /EHsc 01.hello_server_win.c /Fe:hServerWin.exe /link ws2_32.lib && hServerWin

cl /EHsc 01.hello_client_win.c /Fe:hClientWin.exe /link ws2_32.lib && hClientWin
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值