《TCP/IP网络编程》第1章 理解网络编程和套接字
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