[C语言] Socket编程简单例子/Client+Server

一、原理

=====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服务器端:

#include <Winsock2.h>
#include <stdio.h>

int main()
{
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;
 
 wVersionRequested = MAKEWORD( 1, 1 );
 
 err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 ) {
  return -1;
 }
 

 if ( LOBYTE( wsaData.wVersion ) != 1 ||
        HIBYTE( wsaData.wVersion ) != 1 ) {
  WSACleanup( );
  return -1; 
 }
 SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);

 SOCKADDR_IN addrSrv;
 addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
 addrSrv.sin_family=AF_INET;
 addrSrv.sin_port=htons(6000);

 bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

 listen(sockSrv,5);

 SOCKADDR_IN addrClient;


 while(1)
 { //循环短连接

  int len=sizeof(SOCKADDR);
  SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
  char sendBuf[500];
  sprintf(sendBuf,"Welcome %s link in....",
   inet_ntoa(addrClient.sin_addr));
  send(sockConn,sendBuf,strlen(sendBuf)+1,0);
  char recvBuf[500]={0};
  len=recv(sockConn,recvBuf,500,0);
  printf("\nRecv[%d] %s\n",len,recvBuf);
  closesocket(sockConn);
 }

  WSACleanup( );

   return 0 ;
}

 

2.[WIN32] TCP客户端:

#include <Winsock2.h>
#include <stdio.h>

int main()
{
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;
 
 wVersionRequested = MAKEWORD( 1, 1 );
 
 err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 ) {
  return -1;
 }
 

 if ( LOBYTE( wsaData.wVersion ) != 1 ||
        HIBYTE( wsaData.wVersion ) != 1 ) {
  WSACleanup( );
  return -1; 
 }
 SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);

 SOCKADDR_IN addrSrv;
 addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
 addrSrv.sin_family=AF_INET;
 addrSrv.sin_port=htons(6000);
 connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

 char recvBuf[100];
 recv(sockClient,recvBuf,100,0);
 printf("%s\n",recvBuf);
 send(sockClient,"This is lisi",strlen("This is lisi")+1,0);

 closesocket(sockClient);
 WSACleanup();

  return 0;
}

3.[WIN32] UDP服务器端

#include <Winsock2.h>
#include <stdio.h>

void main()
{
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;
 
 wVersionRequested = MAKEWORD( 1, 1 );
 
 err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 ) {
  return;
 }
 

 if ( LOBYTE( wsaData.wVersion ) != 1 ||
        HIBYTE( wsaData.wVersion ) != 1 ) {
  WSACleanup( );
  return; 
 }

 SOCKET sockSrv=socket(AF_INET,SOCK_DGRAM,0);
 SOCKADDR_IN addrSrv;
 addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
 addrSrv.sin_family=AF_INET;
 addrSrv.sin_port=htons(6000);

 bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

 SOCKADDR_IN addrClient;
 int len=sizeof(SOCKADDR);
 char recvBuf[100];

 recvfrom(sockSrv,recvBuf,100,0,(SOCKADDR*)&addrClient,&len);
 printf("%s\n",recvBuf);
 closesocket(sockSrv);
 WSACleanup();
}

4.[WIN32] UDP客户端

#include <Winsock2.h>
#include <stdio.h>

void main()
{
 WORD wVersionRequested;
 WSADATA wsaData;
 int err;
 
 wVersionRequested = MAKEWORD( 1, 1 );
 
 err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 ) {
  return;
 }
 

 if ( LOBYTE( wsaData.wVersion ) != 1 ||
        HIBYTE( wsaData.wVersion ) != 1 ) {
  WSACleanup( );
  return; 
 }

 SOCKET sockClient=socket(AF_INET,SOCK_DGRAM,0);
 SOCKADDR_IN addrSrv;
 addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
 addrSrv.sin_family=AF_INET;
 addrSrv.sin_port=htons(6000);

 sendto(sockClient,"Hello",strlen("Hello")+1,0,
  (SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
 closesocket(sockClient);
 WSACleanup();
}

//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;
}

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单例子,演示如何使用C语言编写一个简单的socket程序,以发送文件。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #define PORT 8080 #define MAX_BUFFER_SIZE 1024 int main(int argc, char const *argv[]) { int sockfd, connfd; struct sockaddr_in servaddr, clientaddr; char buffer[MAX_BUFFER_SIZE]; char filename[256]; int n; // 创建套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { printf("Failed to create socket.\n"); exit(EXIT_FAILURE); } // 设置地址信息 memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_port = htons(PORT); // 绑定端口 if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) { printf("Failed to bind socket.\n"); exit(EXIT_FAILURE); } // 监听端口 if (listen(sockfd, 5) != 0) { printf("Failed to listen on socket.\n"); exit(EXIT_FAILURE); } printf("Server listening on port %d.\n", PORT); // 接受连接 connfd = accept(sockfd, (struct sockaddr *)&clientaddr, (socklen_t*)&n); if (connfd < 0) { printf("Failed to accept connection.\n"); exit(EXIT_FAILURE); } printf("Client connected: %s:%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); // 读取文件名 memset(buffer, 0, MAX_BUFFER_SIZE); read(connfd, buffer, MAX_BUFFER_SIZE); sscanf(buffer, "%s", filename); // 打开文件 int fd = open(filename, O_RDONLY); if (fd < 0) { printf("Failed to open file.\n"); exit(EXIT_FAILURE); } // 发送文件内容 memset(buffer, 0, MAX_BUFFER_SIZE); while ((n = read(fd, buffer, MAX_BUFFER_SIZE)) > 0) { if (write(connfd, buffer, n) < 0) { printf("Failed to send file.\n"); exit(EXIT_FAILURE); } memset(buffer, 0, MAX_BUFFER_SIZE); } printf("File sent successfully.\n"); // 关闭连接和套接字 close(connfd); close(sockfd); return 0; } ``` 该程序的工作流程如下: 1. 创建套接字并绑定端口。 2. 监听端口并等待连接。 3. 接受连接,并读取客户端发送的文件名。 4. 打开文件并读取文件内容。 5. 将文件内容写入套接字,发送给客户端。 6. 关闭连接和套接字。 这是一个非常简单例子,实际中可能需要添加更多的错误检查和异常处理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值