一、原理
=====1.基于TCP协议的服务器端程序流程:=======
1)创建套接字(socket)
2)绑定套接字(bind)
3)将套接字设为监听,准备接收客户请求(listen)
4)等待客户请求的到来,当请求到来后,接受请求,返回一个对应于此次连接的套接字(accept)
5)用返回的套接字与客户端进行通信(send/recv)
6)返回,等待另一客户请求
7)关闭套接字
====2.基于TCP协议的客户端程序流程:=======
1)创建套接字(socket)
2)向服务器发出连接请求(connect)
3)和服务器端进行通信(send/recv)
4)关闭套接字
在服务器端调用accept函数时,程序就会等待客户端调用connect函数发出连接请求,然后接收请求,于是双方就建立了连接,之后,服务器端和客户端就可以利用send和recv函数进行通信了。
#define StartThread(thrFun) CloseHandle(CreateThread(NULL,0,thrFun,NULL,0,NULL))
DWORD WINAPI _FuncThread(LPVOID param); //供参考的全局线程函数
======3.基于UDP的服务器端编写======
1)创建套接字(socket)
2)绑定(bind)
3)等待接收数据(recvfrom)
4)关闭套接字
4.基于UDP的客户端编写
1)创建套接字(socket)
2)向服务器发送数据(sendto)
3)关闭套接字
在所有的套接字编程中第一步都是加载套接字库(WSAStartup)
对于每一个WSAStartup函数的成功调用,在最后都要对应一个WSACleanUp调用。
//#pragma warning(disable:4996) //提高兼容性
二、源码:
1.[WIN32] TCP服务器端:
|
2.[WIN32] TCP客户端:
|
3.[WIN32] UDP服务器端
|
4.[WIN32] UDP客户端
|
//C语言做post请求demo
BOOL PostHttp_Login(SOCKET sock,CString &tokenOutStr)
{
CString postData;
CString str, contentStr;
tokenOutStr = "";
postData = "POST /api/auth/SignIn HTTP/1.1\r\n";
str.Format("Host: %s:%d\r\n",HOST_ADDR,HOST_PORT );
postData += str; //网址+端口
postData += "User-Agent: python-requests/2.28.2\r\n";
postData += "Accept-Encoding: gzip, deflate\r\n";
postData += "Accept: */*\r\n";
postData += "Connection: keep-alive\r\n";
postData += "Content-Type: application/json\r\n";
contentStr.Format("{\"USER\":\"%s\",\"Pwd\":\"%s\"}", g_str_account, g_str_key);
str.Format("Content-Length: %d\r\n\r\n", contentStr.GetLength());
postData += str;
postData += contentStr;
send(sock, postData, postData.GetLength(), 0);
Println("POST_API:>\r\n%s\r\n==============\r\n",postData);
char recvBuf[1024*5] = { 0 };
int len = 0;
int tryTm = 0;
CString retStr;
while (1) {
len = recv(sock, recvBuf, sizeof(recvBuf), 0);
Println("recv_len[%d]", len);
if (len <= 0)
{
Sleep(100);
if (tryTm++ > 30)//超时设置
{
AddTextln("Post ret fail!");
return FALSE;
}
continue;
}
else
{
recvBuf[len] = 0;
Println("[RECV](%d):%s",len,recvBuf);
}
recvBuf[len] = 0;
retStr = "";
EasyJson_GetString(recvBuf,"Token", retStr);
if (retStr != "")
{
tokenOutStr = retStr;
Println("GotToken(%d)=[%s]", len, retStr);
break;
}
else
{
Println("JSON_Err(%d):[%s]", len,recvBuf);
return FALSE;
}
}
return TRUE;
}
[Linux] TCP 服务端:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#define SERVER_PORT (8080)
void dump_hex(char *buf,int len,char *info_str)
{
printf("%s(%d): ",info_str,len);
for(int i=0;i<len;i++)
{
printf("%02x ",(uint8_t)buf[i]);
}
printf("\r\n");
}
int thread_server() {
// 创建套接字
int server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
// 在server_sock绑定bind之前,设置其端口复用
int opt = 1;
setsockopt( server_sock, SOL_SOCKET,SO_REUSEADDR,
(const void *)&opt, sizeof(opt) );
// 设置服务器地址信息
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;
// 绑定套接字到服务器地址
if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
// 监听连接请求
if (listen(server_sock, 5) == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
loop:
printf("Server port: %d,listenning...\n",SERVER_PORT );
// 接受客户端连接请求
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_len);
if (client_sock == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
printf("Client connected,todo recv work.\n");
// 在这里可以进行与客户端的数据收发交互
int sz = 0;
long total = 0;
char rxBuf[1024];
while(1)
{
//阻塞式接收client数据
sz=recv(client_sock,rxBuf,sizeof(rxBuf),0);
if(sz<=0)
{
break;
}
total+=sz;
dump_hex(rxBuf,sz,"SrvRecv");
printf("total recv = %ld bytes.\n",total);
usleep(10*1000);
}
close(client_sock);// 关闭client套接字
printf("accept client again.\n");
goto loop;
close(server_sock);//关闭server套接字
return 0;
}
int main() {
pthread_t tid_a;
pthread_create(&tid_a, NULL, thread_server, NULL);
while(1)
{
//stop here
sleep(1) ;
}
return 0;
}